55 lines
1.5 KiB
TypeScript
55 lines
1.5 KiB
TypeScript
// Lightweight in-memory queue for human-readable system events that should be
|
|
// prefixed to the next main-session prompt/heartbeat. We intentionally avoid
|
|
// persistence to keep events ephemeral.
|
|
|
|
type SystemEvent = { text: string; ts: number };
|
|
|
|
const MAX_EVENTS = 20;
|
|
const queue: SystemEvent[] = [];
|
|
let lastText: string | null = null;
|
|
let lastContextKey: string | null = null;
|
|
|
|
type SystemEventOptions = {
|
|
contextKey?: string | null;
|
|
};
|
|
|
|
function normalizeContextKey(key?: string | null): string | null {
|
|
if (!key) return null;
|
|
const trimmed = key.trim();
|
|
if (!trimmed) return null;
|
|
return trimmed.toLowerCase();
|
|
}
|
|
|
|
export function isSystemEventContextChanged(
|
|
contextKey?: string | null,
|
|
): boolean {
|
|
const normalized = normalizeContextKey(contextKey);
|
|
return normalized !== lastContextKey;
|
|
}
|
|
|
|
export function enqueueSystemEvent(text: string, options?: SystemEventOptions) {
|
|
const cleaned = text.trim();
|
|
if (!cleaned) return;
|
|
lastContextKey = normalizeContextKey(options?.contextKey);
|
|
if (lastText === cleaned) return; // skip consecutive duplicates
|
|
lastText = cleaned;
|
|
queue.push({ text: cleaned, ts: Date.now() });
|
|
if (queue.length > MAX_EVENTS) queue.shift();
|
|
}
|
|
|
|
export function drainSystemEvents(): string[] {
|
|
const out = queue.map((e) => e.text);
|
|
queue.length = 0;
|
|
lastText = null;
|
|
lastContextKey = null;
|
|
return out;
|
|
}
|
|
|
|
export function peekSystemEvents(): string[] {
|
|
return queue.map((e) => e.text);
|
|
}
|
|
|
|
export function hasSystemEvents() {
|
|
return queue.length > 0;
|
|
}
|