mirror of
https://github.com/jlengrand/Maestro.git
synced 2026-03-10 08:31:19 +00:00
fix(notifications): skip custom notification for synopsis messages
Custom notification commands (e.g., TTS, fabric pipelines) should only run for regular AI conversation flow toasts, not for synopsis messages. Added skipCustomNotification flag to Toast interface and set it to true for synopsis toasts. This prevents the notification command from being executed when a synopsis completes, while still showing OS notifications and toast UI.
This commit is contained in:
@@ -361,6 +361,85 @@ describe('ToastContext', () => {
|
||||
expect(window.maestro.notification.speak).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('does not trigger custom notification when skipCustomNotification is true', async () => {
|
||||
vi.useFakeTimers({ shouldAdvanceTime: true });
|
||||
let contextValue: ReturnType<typeof useToast> | null = null;
|
||||
|
||||
renderWithProvider(
|
||||
<ToastConsumer
|
||||
onMount={(ctx) => {
|
||||
contextValue = ctx;
|
||||
}}
|
||||
/>
|
||||
);
|
||||
|
||||
// Enable audio feedback
|
||||
await act(async () => {
|
||||
contextValue!.setAudioFeedback(true, 'say -v Alex');
|
||||
});
|
||||
|
||||
vi.clearAllMocks();
|
||||
|
||||
// Add toast with skipCustomNotification - should NOT trigger speak
|
||||
await act(async () => {
|
||||
contextValue!.addToast({
|
||||
type: 'info',
|
||||
title: 'Synopsis',
|
||||
message: 'Synopsis message that should not be spoken',
|
||||
skipCustomNotification: true,
|
||||
});
|
||||
});
|
||||
|
||||
expect(window.maestro.notification.speak).not.toHaveBeenCalled();
|
||||
// But OS notification should still work
|
||||
expect(window.maestro.notification.show).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('triggers custom notification for regular toasts but not synopsis', async () => {
|
||||
vi.useFakeTimers({ shouldAdvanceTime: true });
|
||||
let contextValue: ReturnType<typeof useToast> | null = null;
|
||||
|
||||
renderWithProvider(
|
||||
<ToastConsumer
|
||||
onMount={(ctx) => {
|
||||
contextValue = ctx;
|
||||
}}
|
||||
/>
|
||||
);
|
||||
|
||||
// Enable audio feedback
|
||||
await act(async () => {
|
||||
contextValue!.setAudioFeedback(true, 'say');
|
||||
});
|
||||
|
||||
vi.clearAllMocks();
|
||||
|
||||
// Add regular task completion toast - SHOULD trigger speak
|
||||
await act(async () => {
|
||||
contextValue!.addToast({
|
||||
type: 'success',
|
||||
title: 'Task Complete',
|
||||
message: 'Regular task completed',
|
||||
});
|
||||
});
|
||||
|
||||
expect(window.maestro.notification.speak).toHaveBeenCalledWith('Regular task completed', 'say');
|
||||
|
||||
vi.clearAllMocks();
|
||||
|
||||
// Add synopsis toast - should NOT trigger speak
|
||||
await act(async () => {
|
||||
contextValue!.addToast({
|
||||
type: 'info',
|
||||
title: 'Synopsis',
|
||||
message: 'Synopsis message',
|
||||
skipCustomNotification: true,
|
||||
});
|
||||
});
|
||||
|
||||
expect(window.maestro.notification.speak).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('shows OS notification when enabled', async () => {
|
||||
vi.useFakeTimers({ shouldAdvanceTime: true });
|
||||
let contextValue: ReturnType<typeof useToast> | null = null;
|
||||
|
||||
@@ -2549,6 +2549,7 @@ function MaestroConsoleInner() {
|
||||
);
|
||||
|
||||
// Show toast for synopsis completion
|
||||
// Skip custom notification - synopsis is not part of regular AI conversation flow
|
||||
addToastRef.current({
|
||||
type: 'info',
|
||||
title: 'Synopsis',
|
||||
@@ -2559,6 +2560,7 @@ function MaestroConsoleInner() {
|
||||
sessionId: synopsisData!.sessionId,
|
||||
tabId: synopsisData!.tabId,
|
||||
tabName: synopsisData!.tabName,
|
||||
skipCustomNotification: true,
|
||||
});
|
||||
|
||||
// Refresh history panel if available
|
||||
|
||||
@@ -18,6 +18,8 @@ export interface Toast {
|
||||
// Action link - clickable URL shown below message (e.g., PR URL)
|
||||
actionUrl?: string; // URL to open when clicked
|
||||
actionLabel?: string; // Label for the action link (defaults to URL)
|
||||
// Skip custom notification command for this toast (used for synopsis messages)
|
||||
skipCustomNotification?: boolean;
|
||||
}
|
||||
|
||||
interface ToastContextType {
|
||||
@@ -118,7 +120,8 @@ export function ToastProvider({
|
||||
});
|
||||
|
||||
// Run custom notification command if enabled and configured
|
||||
if (audioEnabled && audioCommand) {
|
||||
// Skip for toasts that explicitly opt out (e.g., synopsis messages)
|
||||
if (audioEnabled && audioCommand && !toast.skipCustomNotification) {
|
||||
console.log(
|
||||
'[ToastContext] Running custom notification with message:',
|
||||
toast.message,
|
||||
@@ -128,6 +131,8 @@ export function ToastProvider({
|
||||
window.maestro.notification.speak(toast.message, audioCommand).catch((err) => {
|
||||
console.error('[ToastContext] Custom notification failed:', err);
|
||||
});
|
||||
} else if (toast.skipCustomNotification) {
|
||||
console.log('[ToastContext] Custom notification skipped - toast opted out');
|
||||
} else {
|
||||
console.log('[ToastContext] Custom notification skipped - enabled:', audioEnabled, 'command:', audioCommand);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user