aboutsummaryrefslogtreecommitdiffstats
path: root/desktop/assistant
diff options
context:
space:
mode:
authorDanilo M. <danix@danix.xyz>2026-10-22 18:30:27 +0200
committerDanilo M. <danix@danix.xyz>2026-10-22 18:30:27 +0200
commit8edd9865f592ea3808181f4a2803ebf114df0db0 (patch)
treef3c45f6275e25d7d6d5ac5e3c5522baeae718c38 /desktop/assistant
parentf9214ad6c3f59d222dff6529ae75abdf366909c3 (diff)
downloadquickshell-8edd9865f592ea3808181f4a2803ebf114df0db0.tar.gz
quickshell-8edd9865f592ea3808181f4a2803ebf114df0db0.zip
assistant: notify when a reply ends while the card is closed
A reply streams into the canvas state while the card is closed, but nothing said when it was done, so working elsewhere meant checking back. Now a finished or failed turn sends a notification whose Open action brings the card back on that conversation. A stopped reply does not notify: stopping it was the user's own act. notify-send -A blocks until the notification is acted on or dismissed and prints the picked key, so one Process carries it. A newer reply restarts that Process and its stack tag replaces the balloon, which drops the older wait: only the latest reply's Open works. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'desktop/assistant')
-rw-r--r--desktop/assistant/Assistant.qml23
-rw-r--r--desktop/assistant/README.md3
2 files changed, 26 insertions, 0 deletions
diff --git a/desktop/assistant/Assistant.qml b/desktop/assistant/Assistant.qml
index c4d0771..33616ad 100644
--- a/desktop/assistant/Assistant.qml
+++ b/desktop/assistant/Assistant.qml
@@ -405,6 +405,7 @@ Scope {
}
if (!e.stopped) root.convId = e.id;
root.lastActive = Date.now();
+ if (!e.stopped && i >= 0) root.notifyDone(turns.get(i).reply);
break;
case "progress": if (root.opDaemon) root.opChars = e.chars; break;
case "written":
@@ -424,6 +425,7 @@ Scope {
root.flush();
turns.setProperty(i, "error", e.message);
turns.setProperty(i, "live", false);
+ root.notifyDone(e.message);
} else {
root.notice = e.message;
}
@@ -440,6 +442,27 @@ Scope {
}
}
+ // A reply that ends while the card is closed says so, and clicking the
+ // notification opens the card on it. notify-send -A waits until the
+ // notification is acted on or dismissed and prints the picked action.
+ // ponytail: one Process, so a newer reply's notification takes over
+ // (the stack tag replaces the balloon, and restarting drops the old wait).
+ function notifyDone(body) {
+ if (root.open) return;
+ notifyProc.command = ["notify-send", "--app-name=Assistant", "--icon=dialog-information",
+ "-h", "string:x-dunst-stack-tag:assistant", "-A", "default=Open",
+ "Assistant replied", body.slice(0, 200)];
+ notifyProc.running = false;
+ notifyProc.running = true;
+ }
+
+ Process {
+ id: notifyProc
+ stdout: StdioCollector {
+ onStreamFinished: if (text.trim() === "default") root.show()
+ }
+ }
+
Timer {
interval: 50
repeat: true
diff --git a/desktop/assistant/README.md b/desktop/assistant/README.md
index be95eb7..377796c 100644
--- a/desktop/assistant/README.md
+++ b/desktop/assistant/README.md
@@ -60,6 +60,9 @@ Notes:
`ServerNotFoundError` warning each time.
- **`tools` is a comma-joined string role.** A ListModel role holding an
array becomes a nested model, which `setProperty` cannot append to.
+- **A reply that ends while the card is closed notifies.** Its action,
+ Open, brings the card back on that conversation. A stopped reply does
+ not notify; a failed one does, with the error as its body.
- **A stopped reply is shown, not kept.** The daemon does not save a
partial turn, so it is gone after the next reopen or restart.
- **Only an error marked `turn` ends a reply.** Every client sees every