Skip to content

Commit b79a491

Browse files
Make mic prompt confirm likely event
Use nearby calendar context to ask a direct human-readable question and confirm the detected event without an options menu.
1 parent 34cbd65 commit b79a491

5 files changed

Lines changed: 216 additions & 40 deletions

File tree

apps/desktop/src/devtools-panel/host.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -264,21 +264,21 @@ function useDevtoolsPanelActions() {
264264
const showMicOptionsNotification = useCallback(async () => {
265265
await notificationCommands.showNotification({
266266
key: `devtool-mic-options-${crypto.randomUUID()}`,
267-
title: "Are you in a meeting?",
267+
title: "Are you in Design sync right now?",
268268
message: "",
269269
timeout: { secs: 15, nanos: 0 },
270270
source: {
271271
type: "mic_detected",
272272
app_names: ["Zoom", "Google Chrome"],
273273
app_ids: ["us.zoom.xos", "com.google.Chrome"],
274-
event_ids: [],
274+
event_ids: ["devtool-event-1"],
275275
},
276276
start_time: null,
277277
participants: null,
278278
event_details: null,
279-
action_label: null,
279+
action_label: "Yes",
280280
action_variant: null,
281-
options: ["Design sync", "Customer call"],
281+
options: null,
282282
footer: {
283283
text: "Ignore Zoom and Chrome?",
284284
actionLabel: "Yes",

apps/desktop/src/services/event-listeners.test.tsx

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -325,7 +325,7 @@ describe("EventListeners notification events", () => {
325325
});
326326
});
327327

328-
test("notification_confirm with mic_detected source sets triggerAppIds (regression: #5120 confirm path)", async () => {
328+
test("notification_confirm with mic_detected source opens detected event and sets triggerAppIds", async () => {
329329
useMainStoreMock.mockReturnValue({} as never);
330330

331331
render(<EventListeners />);
@@ -344,13 +344,22 @@ describe("EventListeners notification events", () => {
344344
type: "mic_detected",
345345
app_names: ["Zoom"],
346346
app_ids: ["us.zoom.xos"],
347-
event_ids: [],
347+
event_ids: ["event-1"],
348348
},
349349
},
350350
});
351351

352+
expect(getOrCreateSessionForEventIdMock).toHaveBeenCalledWith(
353+
{},
354+
"event-1",
355+
);
356+
expect(createSessionMock).not.toHaveBeenCalled();
352357
expect(setTriggerAppIdsMock).toHaveBeenCalledWith(["us.zoom.xos"]);
353-
expect(openNewMock).toHaveBeenCalledTimes(1);
358+
expect(openNewMock).toHaveBeenCalledWith({
359+
type: "sessions",
360+
id: "session-event",
361+
state: { view: null, autoStart: true },
362+
});
354363
});
355364

356365
test("notification_option_selected with mic_detected source sets triggerAppIds", async () => {

apps/desktop/src/services/event-listeners.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -376,7 +376,9 @@ function useNotificationEvents() {
376376
const eventId =
377377
payload.source?.type === "calendar_event"
378378
? payload.source.event_id
379-
: null;
379+
: payload.source?.type === "mic_detected"
380+
? (payload.source.event_ids?.[0] ?? null)
381+
: null;
380382
const sourceSessionId =
381383
payload.source?.type === "session"
382384
? payload.source.session_id

apps/desktop/src/stt/contexts.test.tsx

Lines changed: 119 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ function mockNearbyEventStore(event: {
9595
meeting_link?: string;
9696
location?: string;
9797
description?: string;
98+
participants_json?: string;
9899
is_all_day?: boolean;
99100
}) {
100101
return mockNearbyEventStoreMany([event]);
@@ -108,6 +109,7 @@ function mockNearbyEventStoreMany(
108109
meeting_link?: string;
109110
location?: string;
110111
description?: string;
112+
participants_json?: string;
111113
is_all_day?: boolean;
112114
}>,
113115
) {
@@ -126,6 +128,7 @@ function mockNearbyEventStoreMany(
126128
meeting_link: event.meeting_link,
127129
location: event.location,
128130
description: event.description,
131+
participants_json: event.participants_json,
129132
is_all_day: event.is_all_day ?? false,
130133
};
131134
}),
@@ -784,7 +787,9 @@ describe("ListenerProvider detect events", () => {
784787
app_ids: ["at.studio.AsideBrowser"],
785788
event_ids: ["event-1"],
786789
},
787-
options: ["Design sync"],
790+
title: "Are you in Design sync right now?",
791+
action_label: "Yes",
792+
options: null,
788793
footer: {
789794
text: "Ignore Google Meet?",
790795
actionLabel: "Yes",
@@ -802,6 +807,56 @@ describe("ListenerProvider detect events", () => {
802807
);
803808
});
804809

810+
test("uses event participants for nearby mic notification copy", async () => {
811+
const store = createListenerStore();
812+
813+
vi.useFakeTimers();
814+
vi.setSystemTime(new Date("2026-06-24T02:09:00.000Z"));
815+
(useStoreMock as any).mockReturnValue(
816+
mockNearbyEventStore({
817+
title: "Design sync",
818+
started_at: "2026-06-24T02:09:00.000Z",
819+
participants_json: JSON.stringify([
820+
{ name: "John", email: "john@example.com", is_current_user: true },
821+
{ name: "Artem", email: "artem@example.com" },
822+
]),
823+
}),
824+
);
825+
826+
render(
827+
<ListenerProvider store={store}>
828+
<div>child</div>
829+
</ListenerProvider>,
830+
);
831+
832+
await vi.waitFor(() => expect(listenMock).toHaveBeenCalledTimes(1));
833+
834+
const handler = listenMock.mock.calls[0]?.[0];
835+
expect(handler).toBeTypeOf("function");
836+
837+
handler({
838+
payload: {
839+
type: "micDetected",
840+
key: "mic-1",
841+
apps: [{ id: "us.zoom.xos", name: "Zoom" }],
842+
duration_secs: 15,
843+
},
844+
});
845+
846+
await vi.waitFor(() =>
847+
expect(showNotificationMock).toHaveBeenCalledWith(
848+
expect.objectContaining({
849+
title: "Are you talking to Artem right now?",
850+
source: expect.objectContaining({
851+
event_ids: ["event-1"],
852+
}),
853+
action_label: "Yes",
854+
options: null,
855+
}),
856+
),
857+
);
858+
});
859+
805860
test("detects Microsoft Teams live join links for browser mic notifications", async () => {
806861
const store = createListenerStore();
807862

@@ -902,8 +957,11 @@ describe("ListenerProvider detect events", () => {
902957
expect.objectContaining({
903958
source: expect.objectContaining({
904959
app_names: ["Google Meet"],
905-
event_ids: ["event-1", "event-2"],
960+
event_ids: ["event-2"],
906961
}),
962+
title: "Are you in Design sync right now?",
963+
action_label: "Yes",
964+
options: null,
907965
footer: expect.objectContaining({
908966
text: "Ignore Google Meet?",
909967
}),
@@ -916,6 +974,62 @@ describe("ListenerProvider detect events", () => {
916974
);
917975
});
918976

977+
test("does not infer browser platform from a different nearby event", async () => {
978+
const store = createListenerStore();
979+
980+
vi.useFakeTimers();
981+
vi.setSystemTime(new Date("2026-06-24T02:09:00.000Z"));
982+
(useStoreMock as any).mockReturnValue(
983+
mockNearbyEventStoreMany([
984+
{
985+
title: "Sales sync",
986+
started_at: "2026-06-24T02:09:00.000Z",
987+
},
988+
{
989+
title: "Design sync",
990+
started_at: "2026-06-24T02:10:00.000Z",
991+
meeting_link: "https://meet.google.com/abc-defg-hij",
992+
},
993+
]),
994+
);
995+
996+
render(
997+
<ListenerProvider store={store}>
998+
<div>child</div>
999+
</ListenerProvider>,
1000+
);
1001+
1002+
await vi.waitFor(() => expect(listenMock).toHaveBeenCalledTimes(1));
1003+
1004+
const handler = listenMock.mock.calls[0]?.[0];
1005+
expect(handler).toBeTypeOf("function");
1006+
1007+
handler({
1008+
payload: {
1009+
type: "micDetected",
1010+
key: "mic-1",
1011+
apps: [{ id: "com.google.Chrome", name: "Google Chrome" }],
1012+
duration_secs: 15,
1013+
},
1014+
});
1015+
1016+
await vi.waitFor(() =>
1017+
expect(showNotificationMock).toHaveBeenCalledWith(
1018+
expect.objectContaining({
1019+
source: expect.objectContaining({
1020+
app_names: ["Google Chrome"],
1021+
event_ids: ["event-1"],
1022+
}),
1023+
title: "Are you in Sales sync right now?",
1024+
footer: expect.objectContaining({
1025+
text: "Ignore Google Chrome?",
1026+
}),
1027+
icon: { type: "bundle_id", bundle_id: "com.google.Chrome" },
1028+
}),
1029+
),
1030+
);
1031+
});
1032+
9191033
test("does not infer chat platforms from incidental calendar text", async () => {
9201034
const store = createListenerStore();
9211035

@@ -1191,6 +1305,9 @@ describe("ListenerProvider detect events", () => {
11911305
app_ids: ["at.studio.AsideBrowser"],
11921306
event_ids: ["event-1"],
11931307
}),
1308+
title: "Are you in Founder call right now?",
1309+
action_label: "Yes",
1310+
options: null,
11941311
footer: expect.objectContaining({
11951312
text: "Ignore Cal Video?",
11961313
icon: {

0 commit comments

Comments
 (0)