fix(nextcloud-talk): dispatch react action so agents can send reactions (#70110)#72348
Conversation
Greptile SummaryThis PR wires the existing Confidence Score: 4/5Safe to merge; the only findings are P2 style/test-naming issues with no runtime impact. All findings are P2: a discarded-return-value pattern that is harmless given current resolveReactionMessageId semantics, and a test whose description doesn't match its mock. No P0/P1 issues found. The SSRF guard is intact, the signature flow is correct, and the new adapter faithfully mirrors the Signal pattern. No files require special attention for blocking concerns. Prompt To Fix All With AIThis is a comment left during a code review.
Path: extensions/nextcloud-talk/src/message-actions.ts
Line: 54-58
Comment:
**Discarded return value obscures the null-fallback logic**
`readStringParam` is called for its throw side-effect only; its return value is silently discarded. If `resolveReactionMessageId` ever returned `null` while `params.messageId` is still present (e.g. a future change to `resolveReactionMessageId`'s semantics), execution would fall through to `String(null)` → `"null"` and silently send a reaction with messageId `"null"`. The Signal adapter avoids this by converting and guarding in one step:
```typescript
const messageIdRaw = resolveReactionMessageId({ args: params, toolContext });
const messageId = messageIdRaw != null ? String(messageIdRaw) : null;
if (!messageId) {
// throws – same user-visible error, no discarded return value
readStringParam(params, "messageId", { required: true });
}
```
How can I resolve this? If you propose a fix, please make it concise.
---
This is a comment left during a code review.
Path: extensions/nextcloud-talk/src/message-actions.test.ts
Line: 86-96
Comment:
**Test description does not match its mock setup**
The test is titled `"returns null when account is disabled"` but the mock returns `[]` (empty list), which is identical to the `"returns null when no accounts are configured"` test above it. The intent was presumably to verify that a disabled account (one that passes through `listEnabledNextcloudTalkAccounts` but fails `isAccountConfigured`) is rejected. As written, `disabledAccount` is never exercised through the `listEnabled…` path, leaving that branch untested.
```typescript
it("returns null when account is disabled", () => {
hoisted.listEnabledNextcloudTalkAccounts.mockReturnValue([disabledAccount]);
// ...
```
How can I resolve this? If you propose a fix, please make it concise.Reviews (1): Last reviewed commit: "test(nextcloud-talk): cover reaction sen..." | Re-trigger Greptile |
|
Codex review: passed. Workflow note: Future ClawSweeper reviews update this same comment in place. How this review workflow works
Summary Reproducibility: yes. Source inspection on current main shows Nextcloud Talk advertises reactions and has a guarded reaction sender, but the plugin lacks PR rating What the crustacean ranks mean
Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics. PR egg Rarity: 🥚 common. What is this egg doing here?
Real behavior proof Risk before merge Maintainer options:
Next step before merge Security Review detailsBest possible solution: Land this Nextcloud Talk-owned action adapter after exact-head checks pass, then close #70110 as fixed by the merge. Do we have a high-confidence way to reproduce the issue? Yes. Source inspection on current main shows Nextcloud Talk advertises reactions and has a guarded reaction sender, but the plugin lacks Is this the best way to solve the issue? Yes. A Nextcloud Talk-owned Label justifications:
What I checked:
Likely related people:
Codex review notes: model gpt-5.5, reasoning high; reviewed against 44c6ad7dce27. |
ac2243a to
7305f78
Compare
7305f78 to
ef721c4
Compare
…st coverage (openclaw#70110 review)
… adding (openclaw#70110 review) The handler read only `emoji` and unconditionally called the add-reaction sender, so a caller passing `{ remove: true, emoji: "👍" }` got the opposite of what they requested. Nextcloud Talk's DELETE-reaction path is not wired yet, so reject `remove: true` with a clear error instead of silently performing an add. Adds explicit tests for both the rejection and the remove:false path. Made-with: Cursor
…anup Main commit 22a74de ("refactor: remove unused channel utilities") removed the listEnabledNextcloudTalkAccounts helper from accounts.ts because it was unused on main. This PR was the only caller, so main's removal broke the build (rolldown MISSING_EXPORT, CodeQL "invocation of non-function") once the PR was merged against current main. Replace the single call site with an inline list-ids + resolve + some(filter) chain built from the remaining exported primitives (listNextcloudTalkAccountIds + resolveNextcloudTalkAccount). Update the test mock boundary to match. Made-with: Cursor
ef721c4 to
9817fed
Compare
|
Addressed the Real behavior proof feedback from the ClawSweeper review above. The PR body now includes a new adapter-path proof block (see "[1] Adapter-path proof" under Real Behavior Proof) where a Node driver imports the actual Also rebased onto current |
|
@clawsweeper automerge |
|
🦞✅ Source: What merged:
Automerge notes:
The automerge loop is complete. Automerge progress:
|
…ns (openclaw#70110) (openclaw#72348) Summary: - This PR adds and registers a Nextcloud Talk message action adapter for add-only reactions, updates reaction docs, and adds adapter plus sender tests. - Reproducibility: yes. Source inspection on current main shows Nextcloud Talk advertises reactions and has a ... ion sender, but the plugin lacks `actions.handleAction`, so shared `react` dispatch has no channel handler. Automerge notes: - PR branch already contained follow-up commit before automerge: test(nextcloud-talk): cover reaction sender request path - PR branch already contained follow-up commit before automerge: fix(nextcloud-talk): harden react null-guard; fix disabled-account te… - PR branch already contained follow-up commit before automerge: fix(nextcloud-talk): reject react remove requests instead of silently… - PR branch already contained follow-up commit before automerge: fix(nextcloud-talk): inline listEnabledAccounts helper after main cle… - PR branch already contained follow-up commit before automerge: docs(nextcloud-talk): note add-only react support in reactions and me… Validation: - ClawSweeper review passed for head 9817fed. - Required merge gates passed before the squash merge. Prepared head SHA: 9817fed Review: openclaw#72348 (comment) Co-authored-by: NW <[email protected]> Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com> Approved-by: takhoffman Co-authored-by: takhoffman <[email protected]>
…ns (#70110) (#72348) Summary: - This PR adds and registers a Nextcloud Talk message action adapter for add-only reactions, updates reaction docs, and adds adapter plus sender tests. - Reproducibility: yes. Source inspection on current main shows Nextcloud Talk advertises reactions and has a ... ion sender, but the plugin lacks `actions.handleAction`, so shared `react` dispatch has no channel handler. Automerge notes: - PR branch already contained follow-up commit before automerge: test(nextcloud-talk): cover reaction sender request path - PR branch already contained follow-up commit before automerge: fix(nextcloud-talk): harden react null-guard; fix disabled-account te… - PR branch already contained follow-up commit before automerge: fix(nextcloud-talk): reject react remove requests instead of silently… - PR branch already contained follow-up commit before automerge: fix(nextcloud-talk): inline listEnabledAccounts helper after main cle… - PR branch already contained follow-up commit before automerge: docs(nextcloud-talk): note add-only react support in reactions and me… Validation: - ClawSweeper review passed for head 9817fed842c69afe55562ab6a3388301582c3fc3. - Required merge gates passed before the squash merge. Prepared head SHA: 9817fed842c69afe55562ab6a3388301582c3fc3 Review: openclaw/openclaw#72348 (comment) Co-authored-by: NW <[email protected]> Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com> Approved-by: takhoffman Co-authored-by: takhoffman <[email protected]>
…ns (#70110) (#72348) Summary: - This PR adds and registers a Nextcloud Talk message action adapter for add-only reactions, updates reaction docs, and adds adapter plus sender tests. - Reproducibility: yes. Source inspection on current main shows Nextcloud Talk advertises reactions and has a ... ion sender, but the plugin lacks `actions.handleAction`, so shared `react` dispatch has no channel handler. Automerge notes: - PR branch already contained follow-up commit before automerge: test(nextcloud-talk): cover reaction sender request path - PR branch already contained follow-up commit before automerge: fix(nextcloud-talk): harden react null-guard; fix disabled-account te… - PR branch already contained follow-up commit before automerge: fix(nextcloud-talk): reject react remove requests instead of silently… - PR branch already contained follow-up commit before automerge: fix(nextcloud-talk): inline listEnabledAccounts helper after main cle… - PR branch already contained follow-up commit before automerge: docs(nextcloud-talk): note add-only react support in reactions and me… Validation: - ClawSweeper review passed for head 9817fed842c69afe55562ab6a3388301582c3fc3. - Required merge gates passed before the squash merge. Prepared head SHA: 9817fed842c69afe55562ab6a3388301582c3fc3 Review: openclaw/openclaw#72348 (comment) Co-authored-by: NW <[email protected]> Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com> Approved-by: takhoffman Co-authored-by: takhoffman <[email protected]>
…ns (openclaw#70110) (openclaw#72348) Summary: - This PR adds and registers a Nextcloud Talk message action adapter for add-only reactions, updates reaction docs, and adds adapter plus sender tests. - Reproducibility: yes. Source inspection on current main shows Nextcloud Talk advertises reactions and has a ... ion sender, but the plugin lacks `actions.handleAction`, so shared `react` dispatch has no channel handler. Automerge notes: - PR branch already contained follow-up commit before automerge: test(nextcloud-talk): cover reaction sender request path - PR branch already contained follow-up commit before automerge: fix(nextcloud-talk): harden react null-guard; fix disabled-account te… - PR branch already contained follow-up commit before automerge: fix(nextcloud-talk): reject react remove requests instead of silently… - PR branch already contained follow-up commit before automerge: fix(nextcloud-talk): inline listEnabledAccounts helper after main cle… - PR branch already contained follow-up commit before automerge: docs(nextcloud-talk): note add-only react support in reactions and me… Validation: - ClawSweeper review passed for head 9817fed. - Required merge gates passed before the squash merge. Prepared head SHA: 9817fed Review: openclaw#72348 (comment) Co-authored-by: NW <[email protected]> Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com> Approved-by: takhoffman Co-authored-by: takhoffman <[email protected]>
…ns (openclaw#70110) (openclaw#72348) Summary: - This PR adds and registers a Nextcloud Talk message action adapter for add-only reactions, updates reaction docs, and adds adapter plus sender tests. - Reproducibility: yes. Source inspection on current main shows Nextcloud Talk advertises reactions and has a ... ion sender, but the plugin lacks `actions.handleAction`, so shared `react` dispatch has no channel handler. Automerge notes: - PR branch already contained follow-up commit before automerge: test(nextcloud-talk): cover reaction sender request path - PR branch already contained follow-up commit before automerge: fix(nextcloud-talk): harden react null-guard; fix disabled-account te… - PR branch already contained follow-up commit before automerge: fix(nextcloud-talk): reject react remove requests instead of silently… - PR branch already contained follow-up commit before automerge: fix(nextcloud-talk): inline listEnabledAccounts helper after main cle… - PR branch already contained follow-up commit before automerge: docs(nextcloud-talk): note add-only react support in reactions and me… Validation: - ClawSweeper review passed for head 9817fed. - Required merge gates passed before the squash merge. Prepared head SHA: 9817fed Review: openclaw#72348 (comment) Co-authored-by: NW <[email protected]> Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com> Approved-by: takhoffman Co-authored-by: takhoffman <[email protected]>
…ns (openclaw#70110) (openclaw#72348) Summary: - This PR adds and registers a Nextcloud Talk message action adapter for add-only reactions, updates reaction docs, and adds adapter plus sender tests. - Reproducibility: yes. Source inspection on current main shows Nextcloud Talk advertises reactions and has a ... ion sender, but the plugin lacks `actions.handleAction`, so shared `react` dispatch has no channel handler. Automerge notes: - PR branch already contained follow-up commit before automerge: test(nextcloud-talk): cover reaction sender request path - PR branch already contained follow-up commit before automerge: fix(nextcloud-talk): harden react null-guard; fix disabled-account te… - PR branch already contained follow-up commit before automerge: fix(nextcloud-talk): reject react remove requests instead of silently… - PR branch already contained follow-up commit before automerge: fix(nextcloud-talk): inline listEnabledAccounts helper after main cle… - PR branch already contained follow-up commit before automerge: docs(nextcloud-talk): note add-only react support in reactions and me… Validation: - ClawSweeper review passed for head 9817fed. - Required merge gates passed before the squash merge. Prepared head SHA: 9817fed Review: openclaw#72348 (comment) Co-authored-by: NW <[email protected]> Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com> Approved-by: takhoffman Co-authored-by: takhoffman <[email protected]>
…ns (openclaw#70110) (openclaw#72348) Summary: - This PR adds and registers a Nextcloud Talk message action adapter for add-only reactions, updates reaction docs, and adds adapter plus sender tests. - Reproducibility: yes. Source inspection on current main shows Nextcloud Talk advertises reactions and has a ... ion sender, but the plugin lacks `actions.handleAction`, so shared `react` dispatch has no channel handler. Automerge notes: - PR branch already contained follow-up commit before automerge: test(nextcloud-talk): cover reaction sender request path - PR branch already contained follow-up commit before automerge: fix(nextcloud-talk): harden react null-guard; fix disabled-account te… - PR branch already contained follow-up commit before automerge: fix(nextcloud-talk): reject react remove requests instead of silently… - PR branch already contained follow-up commit before automerge: fix(nextcloud-talk): inline listEnabledAccounts helper after main cle… - PR branch already contained follow-up commit before automerge: docs(nextcloud-talk): note add-only react support in reactions and me… Validation: - ClawSweeper review passed for head 9817fed. - Required merge gates passed before the squash merge. Prepared head SHA: 9817fed Review: openclaw#72348 (comment) Co-authored-by: NW <[email protected]> Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com> Approved-by: takhoffman Co-authored-by: takhoffman <[email protected]>
…ns (openclaw#70110) (openclaw#72348) Summary: - This PR adds and registers a Nextcloud Talk message action adapter for add-only reactions, updates reaction docs, and adds adapter plus sender tests. - Reproducibility: yes. Source inspection on current main shows Nextcloud Talk advertises reactions and has a ... ion sender, but the plugin lacks `actions.handleAction`, so shared `react` dispatch has no channel handler. Automerge notes: - PR branch already contained follow-up commit before automerge: test(nextcloud-talk): cover reaction sender request path - PR branch already contained follow-up commit before automerge: fix(nextcloud-talk): harden react null-guard; fix disabled-account te… - PR branch already contained follow-up commit before automerge: fix(nextcloud-talk): reject react remove requests instead of silently… - PR branch already contained follow-up commit before automerge: fix(nextcloud-talk): inline listEnabledAccounts helper after main cle… - PR branch already contained follow-up commit before automerge: docs(nextcloud-talk): note add-only react support in reactions and me… Validation: - ClawSweeper review passed for head 9817fed. - Required merge gates passed before the squash merge. Prepared head SHA: 9817fed Review: openclaw#72348 (comment) Co-authored-by: NW <[email protected]> Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com> Approved-by: takhoffman Co-authored-by: takhoffman <[email protected]>
…ns (openclaw#70110) (openclaw#72348) Summary: - This PR adds and registers a Nextcloud Talk message action adapter for add-only reactions, updates reaction docs, and adds adapter plus sender tests. - Reproducibility: yes. Source inspection on current main shows Nextcloud Talk advertises reactions and has a ... ion sender, but the plugin lacks `actions.handleAction`, so shared `react` dispatch has no channel handler. Automerge notes: - PR branch already contained follow-up commit before automerge: test(nextcloud-talk): cover reaction sender request path - PR branch already contained follow-up commit before automerge: fix(nextcloud-talk): harden react null-guard; fix disabled-account te… - PR branch already contained follow-up commit before automerge: fix(nextcloud-talk): reject react remove requests instead of silently… - PR branch already contained follow-up commit before automerge: fix(nextcloud-talk): inline listEnabledAccounts helper after main cle… - PR branch already contained follow-up commit before automerge: docs(nextcloud-talk): note add-only react support in reactions and me… Validation: - ClawSweeper review passed for head 9817fed. - Required merge gates passed before the squash merge. Prepared head SHA: 9817fed Review: openclaw#72348 (comment) Co-authored-by: NW <[email protected]> Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com> Approved-by: takhoffman Co-authored-by: takhoffman <[email protected]>
…ns (openclaw#70110) (openclaw#72348) Summary: - This PR adds and registers a Nextcloud Talk message action adapter for add-only reactions, updates reaction docs, and adds adapter plus sender tests. - Reproducibility: yes. Source inspection on current main shows Nextcloud Talk advertises reactions and has a ... ion sender, but the plugin lacks `actions.handleAction`, so shared `react` dispatch has no channel handler. Automerge notes: - PR branch already contained follow-up commit before automerge: test(nextcloud-talk): cover reaction sender request path - PR branch already contained follow-up commit before automerge: fix(nextcloud-talk): harden react null-guard; fix disabled-account te… - PR branch already contained follow-up commit before automerge: fix(nextcloud-talk): reject react remove requests instead of silently… - PR branch already contained follow-up commit before automerge: fix(nextcloud-talk): inline listEnabledAccounts helper after main cle… - PR branch already contained follow-up commit before automerge: docs(nextcloud-talk): note add-only react support in reactions and me… Validation: - ClawSweeper review passed for head 9817fed. - Required merge gates passed before the squash merge. Prepared head SHA: 9817fed Review: openclaw#72348 (comment) Co-authored-by: NW <[email protected]> Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com> Approved-by: takhoffman Co-authored-by: takhoffman <[email protected]>
…ns (openclaw#70110) (openclaw#72348) Summary: - This PR adds and registers a Nextcloud Talk message action adapter for add-only reactions, updates reaction docs, and adds adapter plus sender tests. - Reproducibility: yes. Source inspection on current main shows Nextcloud Talk advertises reactions and has a ... ion sender, but the plugin lacks `actions.handleAction`, so shared `react` dispatch has no channel handler. Automerge notes: - PR branch already contained follow-up commit before automerge: test(nextcloud-talk): cover reaction sender request path - PR branch already contained follow-up commit before automerge: fix(nextcloud-talk): harden react null-guard; fix disabled-account te… - PR branch already contained follow-up commit before automerge: fix(nextcloud-talk): reject react remove requests instead of silently… - PR branch already contained follow-up commit before automerge: fix(nextcloud-talk): inline listEnabledAccounts helper after main cle… - PR branch already contained follow-up commit before automerge: docs(nextcloud-talk): note add-only react support in reactions and me… Validation: - ClawSweeper review passed for head 9817fed. - Required merge gates passed before the squash merge. Prepared head SHA: 9817fed Review: openclaw#72348 (comment) Co-authored-by: NW <[email protected]> Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com> Approved-by: takhoffman Co-authored-by: takhoffman <[email protected]>
…ns (openclaw#70110) (openclaw#72348) Summary: - This PR adds and registers a Nextcloud Talk message action adapter for add-only reactions, updates reaction docs, and adds adapter plus sender tests. - Reproducibility: yes. Source inspection on current main shows Nextcloud Talk advertises reactions and has a ... ion sender, but the plugin lacks `actions.handleAction`, so shared `react` dispatch has no channel handler. Automerge notes: - PR branch already contained follow-up commit before automerge: test(nextcloud-talk): cover reaction sender request path - PR branch already contained follow-up commit before automerge: fix(nextcloud-talk): harden react null-guard; fix disabled-account te… - PR branch already contained follow-up commit before automerge: fix(nextcloud-talk): reject react remove requests instead of silently… - PR branch already contained follow-up commit before automerge: fix(nextcloud-talk): inline listEnabledAccounts helper after main cle… - PR branch already contained follow-up commit before automerge: docs(nextcloud-talk): note add-only react support in reactions and me… Validation: - ClawSweeper review passed for head 9817fed. - Required merge gates passed before the squash merge. Prepared head SHA: 9817fed Review: openclaw#72348 (comment) Co-authored-by: NW <[email protected]> Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com> Approved-by: takhoffman Co-authored-by: takhoffman <[email protected]>
…ns (openclaw#70110) (openclaw#72348) Summary: - This PR adds and registers a Nextcloud Talk message action adapter for add-only reactions, updates reaction docs, and adds adapter plus sender tests. - Reproducibility: yes. Source inspection on current main shows Nextcloud Talk advertises reactions and has a ... ion sender, but the plugin lacks `actions.handleAction`, so shared `react` dispatch has no channel handler. Automerge notes: - PR branch already contained follow-up commit before automerge: test(nextcloud-talk): cover reaction sender request path - PR branch already contained follow-up commit before automerge: fix(nextcloud-talk): harden react null-guard; fix disabled-account te… - PR branch already contained follow-up commit before automerge: fix(nextcloud-talk): reject react remove requests instead of silently… - PR branch already contained follow-up commit before automerge: fix(nextcloud-talk): inline listEnabledAccounts helper after main cle… - PR branch already contained follow-up commit before automerge: docs(nextcloud-talk): note add-only react support in reactions and me… Validation: - ClawSweeper review passed for head 9817fed. - Required merge gates passed before the squash merge. Prepared head SHA: 9817fed Review: openclaw#72348 (comment) Co-authored-by: NW <[email protected]> Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com> Approved-by: takhoffman Co-authored-by: takhoffman <[email protected]>
…ns (openclaw#70110) (openclaw#72348) Summary: - This PR adds and registers a Nextcloud Talk message action adapter for add-only reactions, updates reaction docs, and adds adapter plus sender tests. - Reproducibility: yes. Source inspection on current main shows Nextcloud Talk advertises reactions and has a ... ion sender, but the plugin lacks `actions.handleAction`, so shared `react` dispatch has no channel handler. Automerge notes: - PR branch already contained follow-up commit before automerge: test(nextcloud-talk): cover reaction sender request path - PR branch already contained follow-up commit before automerge: fix(nextcloud-talk): harden react null-guard; fix disabled-account te… - PR branch already contained follow-up commit before automerge: fix(nextcloud-talk): reject react remove requests instead of silently… - PR branch already contained follow-up commit before automerge: fix(nextcloud-talk): inline listEnabledAccounts helper after main cle… - PR branch already contained follow-up commit before automerge: docs(nextcloud-talk): note add-only react support in reactions and me… Validation: - ClawSweeper review passed for head 9817fed. - Required merge gates passed before the squash merge. Prepared head SHA: 9817fed Review: openclaw#72348 (comment) Co-authored-by: NW <[email protected]> Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com> Approved-by: takhoffman Co-authored-by: takhoffman <[email protected]>

Summary
capabilities.reactions: true, but the channel plugin never wired the existingsendReactionNextcloudTalkHTTP sender to the agent-facing action surface. Reporter traced it toextensions/nextcloud-talk/src/send.ts:192("this function is actually never called").ChannelMessageActionAdapteratextensions/nextcloud-talk/src/message-actions.ts(matches the Signal pattern) and registered it viaactions: nextcloudTalkMessageActionsinextensions/nextcloud-talk/src/channel.ts. Added 16 unit tests for the adapter plus 2 tests for the existing reaction HTTP sender (URL/headers/body/signature on success, error surface on non-2xx).sendReactionNextcloudTalkonly implements POST.Change Type
Scope
Linked Issue/PR
Root Cause
extensions/nextcloud-talk/src/channel.tsdid not register anactionsadapter. The reaction HTTP sendersendReactionNextcloudTalkexists, but the only callers were tests — the sharedmessagetool's action dispatcher (src/channels/plugins/message-action-dispatch.ts) never reached this channel forreactbecause noactions.handleActionwas registered. So the agent-visiblecapabilities.reactions: truehad no execution path behind it.capabilities.reactions: truealso exposes areactaction through itsactionsadapter. Not added in this PR; happy to follow up if maintainers want.outbound.attachedResultsblock inchannel.tswiressendTextandsendMedia, but reactions dispatch through theactionsadapter (see Signal/WhatsApp/Matrix), notoutbound. The seam was missing.Regression Test Plan
extensions/nextcloud-talk/src/message-actions.test.ts(new) — 16 tests for the action adapter:describeMessageToolreturnsnullwhen no accounts configured / account disabled / account missing secret or baseUrl.describeMessageToolreturns["send", "react"]when a configured account exists; honorsaccountIdscoping.supportsActiondelegatessendto outbound and ownsreact.handleActioninvokessendReactionNextcloudTalkwith the correct target/messageId/emoji/accountId/cfg.handleActionfalls back totoolContext.currentMessageIdwhenparams.messageIdis absent.handleActionthrows clean errors on missingto/messageId/emoji.handleActionrejectssend(outbound owns it) and unsupported actions; propagates sender errors unchanged.extensions/nextcloud-talk/src/send.cfg-threading.test.ts(extended) — 2 new tests for the reaction HTTP sender:https://.../ocs/v2.php/apps/spreed/api/v1/bot/<token>/reaction/<messageId>, headers (OCS-APIRequest,X-Nextcloud-Talk-Bot-Random/Signature), body{"reaction":"<emoji>"}, and that the signature is computed over the emoji only (not the full JSON body).Nextcloud Talk reaction failed: <status> <body>.User-visible / Behavior Changes
messagetool withaction: "react", matching how Signal / Matrix / WhatsApp / Telegram work.Security Impact
capabilities.reactions: truewas already advertised atextensions/nextcloud-talk/src/channel.ts:77.POST /ocs/v2.php/apps/spreed/api/v1/bot/{token}/reaction/{messageId}is unchanged. Only the path by which it gets called changed.Repro + Verification
Environment
sendReactionNextcloudTalk(adapter tests) and mocked globalfetch(sender tests).Steps (repro of bug on
mainbefore fix)capabilities.reactions: trueexposed.messagetool dispatchesreact→ no handler is registered for Nextcloud-Talk inmessage-action-dispatch.ts→dispatchChannelMessageActionreturnsnull→ reaction silently dropped or surfaces as "action not supported," while the capability flag still says it is.Expected
Reaction POST hits the Talk bot endpoint; emoji appears on the message.
Actual (pre-fix)
No request goes out; reporter confirmed via code inspection that
sendReactionNextcloudTalkis unreachable from the channel plugin.Verification after fix
pnpm test extensions/nextcloud-talk→ 72 passed (was 46 onmainbefore this PR; +26 tests, no skips).pnpm check:changed→ green across tsgo (extensions + extension tests), oxlint, runtime import cycles, and targeted tests.Real Behavior Proof
Behavior or issue addressed: Nextcloud Talk advertises
capabilities.reactions: truebut never wiressendReactionNextcloudTalkinto the channelactionsadapter, so agentreactrequests on Nextcloud Talk silently no-op (issue #70110). This PR registers the missing adapter so the same sharedmessagetool path that other channels use now reaches the Nextcloud Talk reaction HTTP sender.Real environment tested: Live Nextcloud 30.0.17 + Talk (spreed) 20.1.11 server running in a local Docker container (
nextcloud:30-apache, sqlite backend), reachable onhttp://localhost:8081/. Two real Nextcloud accounts (admin,alice), one Talk bot installed viaphp occ talk:bot:installwith--feature webhook --feature response, and a Talk roomopenclaw-proof-roomwith both users plus the bot attached.Exact steps or command run after this patch:
docker compose up -dagainstnextcloud:30-apache(compose file in repro harness).docker exec ... php occ app:install spreed→ installed Talk 20.1.11.docker exec ... php occ user:add alice(with strong password from env).docker exec ... php occ talk:room:create --user admin --user alice --owner admin --description "OpenClaw #70110 proof" "openclaw-proof-room"→ received room token.docker exec ... php occ talk:bot:install OpenClaw <64-hex-secret> <webhook-url> --feature webhook --feature response→ bot id 1;php occ talk:bot:setup 1 <room-token>to attach.curl -u 'alice:<pw>' -H 'OCS-APIRequest: true' -X POST http://localhost:8081/ocs/v2.php/apps/spreed/api/v1/chat/<room-token> -d 'message=Hello%20OpenClaw'→ message id8.node proof-react.mjs) that mirrorsextensions/nextcloud-talk/src/send.ts:sendReactionNextcloudTalkexactly — identical URL composition, identicalgenerateNextcloudTalkSignatureHMAC scheme (HMAC-SHA256(random + reaction, secret)), identical headers, identical{"reaction":"👍"}body — pointed at the live Nextcloud above.adminto confirm server-authoritative state.Evidence after fix:
[1] Adapter-path proof (added 2026-05-18 in response to ClawSweeper review). A small Node driver imported the actual
nextcloudTalkMessageActionsadapter that this PR adds (no mocks of./send.jsor./accounts.js) and invokedhandleAction({ action: "react", ... })against the live Nextcloud. This exercises the changed code path end-to-end:describeMessageTool→supportsAction→handleAction→ param parsing →resolveReactionMessageId→sendReactionNextcloudTalk→ live HTTP. Terminal capture fromnode --import tsx extensions/nextcloud-talk/.proof-adapter.mts:[2] Underlying wire-contract proof (original). Redacted HTTP wire log from a standalone harness that mirrors
sendReactionNextcloudTalk(URL, signature scheme, headers, body) against the same live Nextcloud — kept because it shows the redacted request shape explicitly:[3] Talk web UI screenshot. Server-rendered Talk UI of Alice's message with the
👍 1reaction beneath it after the bot reaction landed:Observed result after fix: The PR's adapter, when invoked with
handleAction({action:"react", ...}), returns{ ok: true, added: "👍" }and the live Nextcloud Talk server independently confirms the reaction is durably attached to the target message (reactions: {"👍":1}on chat readback as a different authenticated user, plus the Talk web UI rendering the reaction). End-to-end, the changed code path wires the agent-facing react action through to a real Nextcloud Talk install.What was not tested:
sendReactionNextcloudTalkonly implements POST. The new adapter explicitly rejectsparams.remove === trueso callers cannot get the opposite of what they asked for, and this is unit-tested.ChannelMessageActionContextshape matching what the gateway dispatcher constructs.Human Verification
src/channels/plugins/types.core.ts,src/plugin-sdk/channel-actions.ts,src/channels/plugins/message-action-dispatch.ts) to confirmChannelMessageActionAdapteris the correct seam and that dispatch falls through tonullwhenactions.handleActionis missing.extensions/signal/src/message-actions.ts).sendReactionNextcloudTalkPOSTs the correct URL/headers/body and that the signature is computed over the reaction string only (matches the comment insend.ts:202).pnpm check:changedend-to-end locally.Real Behavior Proofabove). Server confirmed the reaction is recorded on the target message; no mocks involved in that path.toolContext.currentMessageIdfallback when the model omitsmessageId(common in inbound-reply flows).nullfromdescribeMessageTool.sendReactionNextcloudTalkonly implements POST. The PR explicitly rejectsremove: trueso callers can't get the opposite of what they asked for.Review Conversations
Compatibility / Migration
Risks and Mitigations
--feature reactionwhen the bot was registered.Nextcloud Talk reaction failed: <status> <body>(now covered by a test).extensions/nextcloud-talk/src/setup-surface.ts:44already documents the--feature reactionflag.describeMessageTooladds discovery overhead on large account sets.resolveNextcloudTalkAccountcall (whenaccountIdis given) or onelistEnabledNextcloudTalkAccounts.some(...)short-circuiting check. Mirrors the Signal pattern inextensions/signal/src/message-actions.ts.AI-assisted: yes (Cursor). I read the relevant SDK contracts (
ChannelMessageActionAdapter,ChannelMessageActionContext,dispatchChannelMessageAction,resolveReactionMessageId,readStringParam), verified the canonical pattern against Signal's adapter, and wrote the tests.codex review --base origin/mainwas unavailable in this environment; happy to rerun if a maintainer points to a hosted equivalent.