fix(notifications): use user-friendly title and dedup keys for permission/question notifications
- Change permission notification title from `req.permission || 'Permission requested'`
to the user-friendly 'Agent needs approval'; permission type + patterns now appear
in the body (e.g. 'bash: echo hello') for context.
- Add `dedupeKey: `perm-${req.id}`` and `dedupeKey: `question-${req.id}``
(60 s cooldown) to both events so a SSE reconnect after disconnect() clears state
can't fire a second notification for the same pending request.
- Fix stale CUA-test comment that claimed 'Agent needs approval' did not exist;
fallback assertion already matched correct title; update the comment to reflect
the real events.ts behavior.
Closes #39
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -1140,11 +1140,11 @@ def run_scenario_backgrounded_permission_notification(opencode_url: str, model:
|
|||||||
print(f" [api] WARNING: could not send permission-triggering message: {exc}")
|
print(f" [api] WARNING: could not send permission-triggering message: {exc}")
|
||||||
|
|
||||||
# Phase 4: DETERMINISTIC — poll notification drawer for permission notification.
|
# Phase 4: DETERMINISTIC — poll notification drawer for permission notification.
|
||||||
# The actual notification fired by events.ts has title `req.permission ||
|
# events.ts fires notify({ title: "Agent needs approval", body: "<perm>: <patterns>",
|
||||||
# "Permission requested"` and body `req.patterns` or "A tool needs your approval"
|
# category: "permissions", sessionId }) — only when app is backgrounded (AppState check
|
||||||
# — there is NO "Agent needs approval" string. The only token guaranteed in every
|
# in notifications.ts send()). The only token guaranteed in every dumpsys record is our
|
||||||
# dumpsys record is our package name, so gate on APP_PACKAGE (deterministic) and
|
# package name, so gate on APP_PACKAGE (deterministic); fall back to the notification
|
||||||
# treat the human-readable copy as a secondary signal.
|
# title/body as secondary signals.
|
||||||
print(" [notify] polling notification drawer for permission notification...")
|
print(" [notify] polling notification drawer for permission notification...")
|
||||||
appeared = check_notification_drawer(APP_PACKAGE, timeout=15)
|
appeared = check_notification_drawer(APP_PACKAGE, timeout=15)
|
||||||
if not appeared:
|
if not appeared:
|
||||||
|
|||||||
@@ -269,9 +269,18 @@ export const useEvents = create<EventsState>((set, get) => ({
|
|||||||
}))
|
}))
|
||||||
notify({
|
notify({
|
||||||
category: "permissions",
|
category: "permissions",
|
||||||
title: req.permission || "Permission requested",
|
title: "Agent needs approval",
|
||||||
body: sanitizeBody(req.patterns?.join(", "), "A tool needs your approval"),
|
body: sanitizeBody(
|
||||||
|
req.permission
|
||||||
|
? req.patterns?.length
|
||||||
|
? `${req.permission}: ${req.patterns.join(", ")}`
|
||||||
|
: req.permission
|
||||||
|
: req.patterns?.join(", "),
|
||||||
|
"A tool needs your approval",
|
||||||
|
),
|
||||||
sessionId: req.sessionID,
|
sessionId: req.sessionID,
|
||||||
|
dedupeKey: `perm-${req.id}`,
|
||||||
|
dedupeCooldownMs: 60_000,
|
||||||
})
|
})
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@@ -305,6 +314,8 @@ export const useEvents = create<EventsState>((set, get) => ({
|
|||||||
title: req.questions?.[0]?.header || "Input needed",
|
title: req.questions?.[0]?.header || "Input needed",
|
||||||
body: sanitizeBody(req.questions?.[0]?.question, "The assistant has a question"),
|
body: sanitizeBody(req.questions?.[0]?.question, "The assistant has a question"),
|
||||||
sessionId: req.sessionID,
|
sessionId: req.sessionID,
|
||||||
|
dedupeKey: `question-${req.id}`,
|
||||||
|
dedupeCooldownMs: 60_000,
|
||||||
})
|
})
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user