fix: check window focus before summarization to avoid wasted Zen API calls

When notificationMode is 'hidden-only', the isWindowFocused check now
happens before summarization and template resolution, not after. This
prevents costly Zen API calls for notifications that would be skipped
anyway, and eliminates stale notifications arriving after the user has
already read the response and switched away.
This commit is contained in:
Bohdan Triapitsyn
2026-05-13 17:43:08 +03:00
parent ef2dc8751d
commit 7fb5ad0f48
3 changed files with 29 additions and 0 deletions
+1
View File
@@ -785,6 +785,7 @@ const spawnLocalServer = async () => {
attachSignals: false,
exitOnShutdown: false,
onDesktopNotification: (payload) => maybeShowNativeNotification(payload),
getIsWindowFocused: isAnyWindowFocused,
});
const port = handle.getPort();
+3
View File
@@ -1073,6 +1073,9 @@ async function main(options = {}) {
if (typeof options.onDesktopNotification === 'function') {
notificationEmitterRuntime.setOnDesktopNotification(options.onDesktopNotification);
}
if (typeof options.getIsWindowFocused === 'function') {
notificationTriggerRuntime.setGetIsWindowFocused(options.getIsWindowFocused);
}
console.log(`Starting OpenChamber on port ${port === 0 ? 'auto' : port}`);
@@ -16,6 +16,14 @@ export const createNotificationTriggerRuntime = (deps) => {
getOpenCodeAuthHeaders,
} = deps;
let getIsWindowFocused = typeof deps.getIsWindowFocused === 'function'
? deps.getIsWindowFocused
: null;
const setGetIsWindowFocused = (cb) => {
getIsWindowFocused = typeof cb === 'function' ? cb : null;
};
const PUSH_READY_COOLDOWN_MS = 5000;
const PUSH_QUESTION_DEBOUNCE_MS = 500;
const PUSH_PERMISSION_DEBOUNCE_MS = 500;
@@ -211,6 +219,10 @@ export const createNotificationTriggerRuntime = (deps) => {
return;
}
if (settings.notificationMode !== 'always' && getIsWindowFocused?.()) {
return;
}
const now = Date.now();
const lastAt = lastReadyNotificationAt.get(sessionId) ?? 0;
if (now - lastAt < PUSH_READY_COOLDOWN_MS) {
@@ -283,6 +295,10 @@ export const createNotificationTriggerRuntime = (deps) => {
const settings = await readSettingsFromDisk();
if (settings.notifyOnError === false) return;
if (settings.notificationMode !== 'always' && getIsWindowFocused?.()) {
return;
}
let title = 'Tool error';
let body = 'An error occurred';
@@ -355,6 +371,10 @@ export const createNotificationTriggerRuntime = (deps) => {
return;
}
if (settings.notificationMode !== 'always' && getIsWindowFocused?.()) {
return;
}
const firstQuestion = payload.properties?.questions?.[0];
const header = typeof firstQuestion?.header === 'string' ? firstQuestion.header.trim() : '';
const questionText = typeof firstQuestion?.question === 'string' ? firstQuestion.question.trim() : '';
@@ -473,6 +493,10 @@ export const createNotificationTriggerRuntime = (deps) => {
return;
}
if (settings.notificationMode !== 'always' && getIsWindowFocused?.()) {
return;
}
const sessionTitle = payload.properties?.sessionTitle;
const permissionText = typeof permission === 'string' && permission.length > 0 ? permission : '';
const fallbackMessage = typeof sessionTitle === 'string' && sessionTitle.trim().length > 0
@@ -543,5 +567,6 @@ export const createNotificationTriggerRuntime = (deps) => {
return {
maybeSendPushForTrigger,
setAutoAcceptSession,
setGetIsWindowFocused,
};
};