fix: deduplicate desktop notifications and tighten notification text extraction

Desktop notifications no longer duplicate when native delivery succeeds
Reasoning chain-of-thought is excluded from notification body text
Untyped message parts are ignored in notification text extraction
This commit is contained in:
Bohdan Triapitsyn
2026-06-16 15:21:27 +03:00
parent 6ea8fb357d
commit 91de51d1a5
7 changed files with 144 additions and 46 deletions
@@ -29,43 +29,51 @@ export const createNotificationEmitterRuntime = (dependencies) => {
const emitDesktopNotification = (payload) => {
const desktopNotifyEnabled = getDesktopNotifyEnabled();
if (!desktopNotifyEnabled) {
return;
return false;
}
if (!payload || typeof payload !== 'object') {
return;
return false;
}
if (onDesktopNotification) {
try {
onDesktopNotification(payload);
return true;
} catch {
// ignore host-side throw
}
return;
return false;
}
try {
// stdout fallback for runtimes that parse the one-line `${prefix}{json}` protocol.
process.stdout.write(`${desktopNotifyPrefix}${JSON.stringify(payload)}\n`);
return true;
} catch {
// ignore
}
return false;
};
const broadcastUiNotification = (payload) => {
const broadcastUiNotification = (payload, options = {}) => {
const desktopNotifyEnabled = getDesktopNotifyEnabled();
if (!payload || typeof payload !== 'object') {
return;
}
const desktopNotificationDelivered = options.desktopNotificationDelivered === true;
const syntheticPayload = {
type: 'openchamber:notification',
properties: {
...payload,
// Tell the UI whether the stdout notification channel is active.
// When true, the desktop UI should skip this SSE notification to avoid duplicates.
// When false, the UI must handle this SSE notification itself.
// Tell local desktop UI whether a native channel already accepted this
// notification. If so, the SSE/WS event is informational only and must
// not create a second OS notification.
desktopNotificationDelivered,
// Legacy marker retained for older clients that only know about stdout.
desktopStdoutActive: desktopNotifyEnabled,
},
};