Skip to content

feat(chat): offer a notification when a reply is ready - #697

Merged
julien-nc merged 12 commits into
nextcloud:mainfrom
WSHAPER:feat/chat-notify-when-ready
Oct 21, 2026
Merged

julien-nc merged 12 commits into
nextcloud:mainfrom
WSHAPER:feat/chat-notify-when-ready

Conversation

@WSHAPER

@WSHAPER WSHAPER commented Oct 13, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #695

Browser notifications need the background push click fix from nextcloud/notifications#3477, implemented in nextcloud/notifications#3478.

Assisted-by: opencode:glm-5.3

Fixes nextcloud#695

Assisted-by: opencode:glm-5.3
Signed-off-by: WSHAPER <42714629+WSHAPER@users.noreply.github.com>
@coderabbitai

coderabbitai Bot commented Oct 13, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Chat tasks now receive chat-specific success or failure notifications with conversation links. The chat interface adds a per-generation notification toggle and browser permission handling. The assistant form also uses a URL session ID to select the chat task type.

Priority: ➖ Normal

Merge Risk: 🟡 Moderate · up to 45e92

On supported Nextcloud 35.0.2, clicking a notification with the chat closed may not open the conversation. Rapid toggle requests can also leave notifications enabled after opt-out, and a failed reply save can still produce a “reply ready” notification. These notification-path issues warrant resolution or explicit acceptance before merging.

Pre-merge checks: Passed 4 · Failed 1

Failed Failed checks: 1 warning

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 20.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 25 functions across 8 files. (1 skipped: … Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed Passed checks: 4 passed
Check name Status Explanation
Title check Passed The title clearly describes the main change: adding notifications when a chat reply is ready.
Description check Passed The description is directly related to the changes. It identifies issue #695 and explains the browser notification dependency on the background push click fix.
Linked Issues check Passed The changes satisfy the coding requirements in #695. InputArea shows a delayed banner during generation, explains that the page can close, and provides a per-reply notify control. `ChattyLLMInputFor…
Out of Scope Changes check Passed The changes remain within #695. The frontend changes implement the banner, delay, dismissal, permission flow, and task-state synchronization. The backend changes implement chat success and failure not…
Full details: Linked Issues check

Explanation

The changes satisfy the coding requirements in #695. InputArea shows a delayed banner during generation, explains that the page can close, and provides a per-reply notify control. ChattyLLMInputForm requests permission and synchronizes the notification state with the active task. Backend listeners send success and failure notifications after reply persistence. Notifier supplies conversation links and a View reply action. URL handling opens the relevant chat. Added unit tests cover notification creation, links, subjects, and chat task detection. Closed-tab click delivery still depends on the external background-push fix named in #695.

Full details: Out of Scope Changes check

Explanation

The changes remain within #695. The frontend changes implement the banner, delay, dismissal, permission flow, and task-state synchronization. The backend changes implement chat success and failure notifications and preserve generic task handling. URL routing and unit tests support the requested notification behavior. No unrelated product change or ignored file appears in the reviewed scope.

Full details: Docstring Coverage

Explanation

Docstring coverage is 20.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 25 functions across 8 files. (1 skipped: 1 unsupported.)

Resolution

Write docstrings for the functions missing them to satisfy the coverage threshold.

  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@WSHAPER
WSHAPER requested a review from julien-nc October 13, 2026 10:55

@julien-nc julien-nc left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the added UI element should be more discreet. On a system that will execute the task in a short time, it feels weird to see this big note card appear.

Maybe only adding a button on the right, next to the submit/audio one, would be enough. We would loose the "you can close the page" explanation text but we would keep the "click this if you want to be notified when the assistant produced a response" as the HTML title of the button.
Wdyt?

Comment thread lib/Service/NotificationService.php Outdated
Comment thread lib/Service/NotificationService.php Outdated
@WSHAPER

WSHAPER commented Oct 13, 2026 •

Copy link
Copy Markdown
Contributor Author

I think the added UI element should be more discreet. On a system that will execute the task in a short time, it feels weird to see this big note card appear.

Maybe only adding a button on the right, next to the submit/audio one, would be enough. We would loose the "you can close the page" explanation text but we would keep the "click this if you want to be notified when the assistant produced a response" as the HTML title of the button. Wdyt?

The prominent banner is deliberate, it follows how Claude does it: the opt-in is one shot and easy to miss when it hides behind a tooltip, and the "you can close the page" part is half of what the issue (Fu) asks for, imo. A bare button with a title attribute would drop that entirely.

But I would agree with the "weird on a quick action" part (from what I assume you mean), so I'd lean towards gating the visibility conditionally. Only issue on my part is a possible scope creep, doing it "properly" would involve context_agent additions.

I'd be up to gating it behind a set 10-15s timer, if that helps. Achieves a comparable compromise with less coupling.

wdyt @julien-nc

@julien-nc

Copy link
Copy Markdown
Member

I'd be up to gating it behind a set 10-15s timer

Sounds good. But then, one cannot immediately enable notification for a task after submitting the message. Fair enough.

The note card label could be improved IMO.
A reply is generated in the background, you can close the assistant. Do you want to be notified when the reply is ready?
Wdyt?

Assisted-by: opencode:glm-5.3
Signed-off-by: WSHAPER <42714629+WSHAPER@users.noreply.github.com>
@WSHAPER

WSHAPER commented Oct 13, 2026

Copy link
Copy Markdown
Contributor Author

I'd be up to gating it behind a set 10-15s timer

Sounds good. But then, one cannot immediately enable notification for a task after submitting the message. Fair enough.

The note card label could be improved IMO. A reply is generated in the background, you can close the assistant. Do you want to be notified when the reply is ready? Wdyt?

I'd keep the current label though: it's one line by design, the longer variant wraps and doubles the card height, and the Notify action next to it is self-explanatory.

Timer gate it is, will push it shortly. The tradeoff after submitting is fine by me.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
tests/unit/Notification/NotifierTest.php (1)

99-150: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Add tests for success and failure with a null target.

The current tests cover only chat subjects. A test with target => null for success would expose the issue at Line 74 of Notifier.php.


ℹ️ Review info
⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 32a9facd-ba9c-4965-a2fc-0902bd98cf50
📥 Commits

Reviewing files that changed from the base of the PR and between d5a4cf0 and 5a01e2b.

📒 Files selected for processing (10)
  • lib/Listener/TaskFailedListener.php
  • lib/Listener/TaskSuccessfulListener.php
  • lib/Notification/Notifier.php
  • lib/Service/NotificationService.php
  • src/components/AssistantTextProcessingForm.vue
  • src/components/ChattyLLM/ChattyLLMInputForm.vue
  • src/components/ChattyLLM/InputArea.vue
  • src/utils.js
  • tests/unit/Notification/NotifierTest.php
  • tests/unit/Service/NotificationServiceTest.php

Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review.

Comment thread lib/Notification/Notifier.php
Comment thread src/components/ChattyLLM/ChattyLLMInputForm.vue
Signed-off-by: WSHAPER <42714629+WSHAPER@users.noreply.github.com>
Assisted-by: opencode:glm-5.3
Signed-off-by: WSHAPER <42714629+WSHAPER@users.noreply.github.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to GitHub limitations.

⚠️ Outside diff range comments (1)

🟡 Minor · Require the background-push click fix for chat notifications. · Notifier.php:413-455

lib/Notification/Notifier.php:413-455
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Require the background-push click fix for chat notifications.

NotificationService::sendNotification() emits chat_success and chat_failure for chat tasks. Notifier assigns the target to both the notification link and the IAction::TYPE_WEB action. When the page is closed, opening that target depends on the Nextcloud notifications background-push click handler.

Nextcloud 35 is supported, but its stable-35 backport of fix #3478 is not merged. A supported deployment can therefore deliver the notification while failing to open the chat. Require a notifications release containing #3478, or add an equivalent local fallback before relying on this behavior.


ℹ️ Review info
⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 0cc06753-dd46-4bef-8730-510b293d2f74
📥 Commits

Reviewing files that changed from the base of the PR and between 5a01e2b and f2fa07d.

📒 Files selected for processing (4)
  • lib/Notification/Notifier.php
  • src/components/ChattyLLM/ChattyLLMInputForm.vue
  • src/components/ChattyLLM/InputArea.vue
  • tests/unit/Notification/NotifierTest.php
🚧 Files skipped from review as they are similar to previous changes (1)
  • tests/unit/Notification/NotifierTest.php

Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review.

@WSHAPER

WSHAPER commented Oct 14, 2026

Copy link
Copy Markdown
Contributor Author

Caution

Some comments are outside the diff and can’t be posted inline due to GitHub limitations.

⚠️ Outside diff range comments (1)

🟡 Minor · Require the background-push click fix for chat notifications. · Notifier.php:413-455

lib/Notification/Notifier.php:413-455
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Require the background-push click fix for chat notifications.
NotificationService::sendNotification() emits chat_success and chat_failure for chat tasks. Notifier assigns the target to both the notification link and the IAction::TYPE_WEB action. When the page is closed, opening that target depends on the Nextcloud notifications background-push click handler.
Nextcloud 35 is supported, but its stable-35 backport of fix #3478 is not merged. A supported deployment can therefore deliver the notification while failing to open the chat. Require a notifications release containing #3478, or add an equivalent local fallback before relying on this behavior.

ℹ️ Review info

Background (closed-tab) notification clicks fully resolve once nextcloud/notifications#3478 ships

Comment thread src/components/ChattyLLM/InputArea.vue Outdated
thinkingText: t('assistant', 'Processing…'),
scheduledText: t('assistant', 'Waiting…'),
submitBtnAriaText: t('assistant', 'Submit'),
notifyBannerText: t('assistant', 'You can close this page. Want to be notified when the reply is ready?'),

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
notifyBannerText: t('assistant', 'You can close this page. Want to be notified when the reply is ready?'),
notifyBannerText: t('assistant', 'You can close this page. Do you want to be notified when the reply is ready?'),

Comment thread src/components/ChattyLLM/InputArea.vue Outdated
Comment on lines +194 to +195
notifyBtnLabel: t('assistant', 'Notify'),
notifyingBtnLabel: t('assistant', 'Notifying'),

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
notifyBtnLabel: t('assistant', 'Notify'),
notifyingBtnLabel: t('assistant', 'Notifying'),
notifyBtnLabel: t('assistant', 'Get notified'),
notifyingBtnLabel: t('assistant', 'Notifying'),

Let's try to stay consistent with what the generic form does. We could add an icon to the button.

  • The icon could be BellOutlineIcon when the notification is disabled and BellRingOutlineIcon when it's on.
  • The button html title could change from No notification to You will be notified.
  • The label can be Get notified at all times IMO
  • Not sure about using the aria-pressed prop. We could conditionally change the variant or just keep secondary and just be happy with the conditional icon

Wdyt?

Comment thread lib/Service/NotificationService.php Outdated
$params = [
'appId' => $task->getAppId(),
'id' => $task->getId(),
'inputs' => $task->getInput(),

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should omit the task input in the notification when it's a chat task. The input can be huge here and we don't use it to render the notification.
This could make the notification system crash if the input is larger than the related column in the notifications table.

- align the notify banner button with the generic task form
- omit the task input from chat notifications
- wrap the notify banner text instead of truncating it

Assisted-by: opencode:glm-5.3
Signed-off-by: WSHAPER <42714629+WSHAPER@users.noreply.github.com>

@julien-nc julien-nc left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • Test issue, simple fix: do not assert that a notification will have the task input

Otherwise, good to go.

The notification service omits the input for chat tasks since it is
never rendered and can overflow the notifications table column.

Signed-off-by: WSHAPER <42714629+WSHAPER@users.noreply.github.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to GitHub limitations.

⚠️ Outside diff range comments (2)

🟡 Minor · Preserve assignment context in generic chat notification links. · Notifier.php:417-431

lib/Notification/Notifier.php:417-431
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Preserve assignment context in generic chat notification links.

When notifyWhenReady is called for an assigned ChattyLLM task, the generic notification path can create a chat_success or chat_failure notification. Its fallback URL contains only sessionId. The assistant then opens chat mode, where assigned sessions are excluded, so the notification does not select the relevant assignment conversation.

Propagate an assignment flag with the generic notification and add isAssignment=true only for assigned sessions. Keep ordinary chat links unchanged.

🟡 Minor · Require notifications support for closed-tab clicks. · Notifier.php:417-431

lib/Notification/Notifier.php:417-431
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Require notifications support for closed-tab clicks.

Notifications v35.0.2 has no background notificationclick handler. The chat notification supplies a WEB action, but the assistant only provides a fallback for task notifications. When the tab is closed, clicking the chat notification can therefore fail to open the conversation.

Declare a minimum notifications release that contains backport #3480, or add an equivalent fallback.


ℹ️ Review info
⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 97f74648-fda5-459d-beac-f4c6972cf655
📥 Commits

Reviewing files that changed from the base of the PR and between f2fa07d and fb5098b.

📒 Files selected for processing: 3
  • lib/Service/NotificationService.php
  • src/components/ChattyLLM/InputArea.vue
  • tests/unit/Service/NotificationServiceTest.php

Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review.

…en-ready

Resolve the ChattyLLM conflicts against the cancel-generation work that
landed upstream (nextcloud#696 + follow-ups):

- unify on upstream's generationTaskId tracking (request sequences,
  pending-cancel handshake, ownership-guarded resets) and layer the
  notify-when-ready state on top: trackGenerationTask() resets the
  toggle, the notify state sync and onBackgroundNotify read
  generationTaskId instead of the now removed currentGenerationTaskId
- InputArea: keep both the notify banner and the stop-generation
  control, and merge the two loading.llmGeneration watchers into one

Assisted-by: opencode:glm-5.3
Signed-off-by: WSHAPER <42714629+WSHAPER@users.noreply.github.com>
The browser permission prompt can stay open long enough for the tracked
generation to end or be replaced: applying the toggle then would target
the wrong task and desync the banner state.

Assisted-by: opencode:glm-5.3
Signed-off-by: WSHAPER <42714629+WSHAPER@users.noreply.github.com>
@WSHAPER

WSHAPER commented Oct 19, 2026 •

Copy link
Copy Markdown
Contributor Author

🟡 Minor · Preserve assignment context in generic chat notification links (Notifier.php:417-431)

When notifyWhenReady is called for an assigned ChattyLLM task, the generic notification path can create a chat_success or chat_failure notification. Its fallback URL contains only sessionId. The assistant then opens chat mode, where assigned sessions are excluded, so the notification does not select the relevant assignment conversation.

I don't think this path is reachable with the current UI:

  • the task listeners only send a notification when a notify-ready row exists for the task, they return early otherwise
  • for chat tasks that row can only be created from the banner/toggle in InputArea, which isn't rendered for assignments (v-if="!isAssignment"), and the task form's notify button doesn't apply to chat tasks
  • assignments already get their own assignment_successful/assignment_failure notifications with isAssignment=true links (ChattyLLMTaskListener → sendAssignmentNotification)

To hit the wrong link you'd have to create a notify-ready row for an assignment task id via the API directly. If that case is worth covering I can pass an assignment flag along, but I'd leave it out otherwise.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

♻️ Duplicate comments: 1
src/components/ChattyLLM/ChattyLLMInputForm.vue: 1

1412-1412: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Check task ownership before applying the update.

If the user switches conversations or starts another generation while setNotifyReady is pending, this callback sets isNotifyEnabled for the old task on the new generation. A fresh permission grant can also schedule an unrelated page reload. Check that generationTaskId === taskId before updating the toggle or scheduling the reload.


ℹ️ Review info
⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 89ae1b04-2bc9-4a43-93a3-fff346e2831c
📥 Commits

Reviewing files that changed from the base of the PR and between fb5098b and f05a6b5.

📒 Files selected for processing: 6
  • lib/Listener/TaskFailedListener.php
  • lib/Listener/TaskSuccessfulListener.php
  • lib/Notification/Notifier.php
  • lib/Service/NotificationService.php
  • src/components/ChattyLLM/ChattyLLMInputForm.vue
  • src/components/ChattyLLM/InputArea.vue

Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review.

Comment thread lib/Listener/TaskSuccessfulListener.php
Comment thread src/components/ChattyLLM/ChattyLLMInputForm.vue
Signed-off-by: WSHAPER <42714629+WSHAPER@users.noreply.github.com>
The notify listeners were registered before the chat persistence
listener, so an opted-in chat task could push the ready notification
before the assistant message is inserted and the user would open a
conversation whose reply does not exist yet. Register ChattyLLMTaskListener
first so the reply is saved before any notification goes out.

Assisted-by: opencode:glm-5.3
Signed-off-by: WSHAPER <42714629+WSHAPER@users.noreply.github.com>
The reload timer after a fresh browser notification grant only checked
isNotifyEnabled: a toggle back to disabled whose request was still
pending kept it true, so the reload could interrupt the opt-out and the
notification stayed enabled server side. Capture the per-request sync id
and let only the newest toggle's response and reload timer apply.

Assisted-by: opencode:glm-5.3
Signed-off-by: WSHAPER <42714629+WSHAPER@users.noreply.github.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1


ℹ️ Review info
⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: c2749bc2-915e-4dc2-99c2-cbd77a097814
📥 Commits

Reviewing files that changed from the base of the PR and between f05a6b5 and 45e921f.

📒 Files selected for processing: 2
  • lib/AppInfo/Application.php
  • src/components/ChattyLLM/ChattyLLMInputForm.vue

Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review.

Comment thread src/components/ChattyLLM/ChattyLLMInputForm.vue
Two overlapping toggle requests could complete out of order server side:
a late enable POST landing after an opt-out DELETE would restore the
notification while the client keeps showing it disabled. Ignore further
toggles while one is in flight, also covering double clicks during the
browser permission prompt.

Assisted-by: opencode:glm-5.3
Signed-off-by: WSHAPER <42714629+WSHAPER@users.noreply.github.com>
@WSHAPER

WSHAPER commented Oct 19, 2026

Copy link
Copy Markdown
Contributor Author

FYI ping: @julien-nc everything should be addressed so far.

@julien-nc
julien-nc self-requested a review October 21, 2026 09:02
@julien-nc
julien-nc merged commit 0911bc1 into nextcloud:main Oct 21, 2026
16 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Chat: offer to notify when a reply is ready, and say the page can be closed

3 participants