feat(nextcloud-talk): reactions, ack emoji, typing indicators, mention parsing#2
feat(nextcloud-talk): reactions, ack emoji, typing indicators, mention parsing#2
Conversation
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: b8a08c3606
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| const result = await processNextcloudTalkReplayGuardedMessage({ | ||
| replayGuard, | ||
| accountId: account.accountId, | ||
| message: reaction, |
There was a problem hiding this comment.
Namespace replay keys for reaction webhooks
This passes reactions through processNextcloudTalkReplayGuardedMessage using the same roomToken + messageId key shape used for normal message webhooks, so reactions collide with already-processed Create events and with other reactions on the same message. In practice, once a message webhook is committed, later Like/Dislike events for that message are treated as duplicates and dropped, which breaks reaction forwarding for common cases.
Useful? React with 👍 / 👎.
| kind: "group", | ||
| id: roomToken, |
There was a problem hiding this comment.
Route DM reactions with direct peer identity
The reaction handler always resolves routes as peer.kind: "group" keyed by roomToken, but DM inbound messages are routed as direct peers keyed by sender id in handleNextcloudTalkInbound. That mismatch means direct-room reactions are written to a different route/session than the originating DM conversation, so per-peer DM routing and session continuity can break (including reactions being handled by a different agent binding).
Useful? React with 👍 / 👎.
- Export parseStructuredNextcloudTalkBody and resolveExplicitNextcloudTalkMention - Rename mentionDebug -> mentionEntries and drop unused explicitMention field from the parsed body struct - Remove verbose per-message debug log line from the hot path - Add inbound.mentions.test.ts with 16 unit tests covering plain text pass-through, structured JSON extraction, malformed JSON fallback, and mention matching (id, mentionId, name, email local-part, case-insensitive, type guard)
…ge body
Nextcloud Talk's structured payload puts mention tokens like {mention0} or
{mention-user1} directly in the message string. Leaving them in effectiveBody
caused two problems:
- Command parsing (hasControlCommand, directives) would not see commands that
follow an @-mention, e.g. "{mention0} /reset" -> "/reset" was never reached.
- A mention-only message ("{mention0}") produced a non-empty prompt dispatched
to the agent, causing spurious replies.
Fix: strip all {key} placeholder tokens whose keys appear in parameters[], then
treat a structured body that is empty after stripping as a mention-only ping and
return early without dispatching.
Also add ParsedNextcloudTalkBody.structured flag to distinguish plain-text
fall-through from a successfully parsed JSON body.
Tests: 2 new cases (mention-only drop, command after mention), updated existing
assertions to reflect stripped text. 18 unit tests, 68 total, all passing.
- Outbound: wire sendReactionNextcloudTalk into a ChannelMessageActionAdapter (nextcloudTalkMessageActions) exposing the 'react' action on the message tool - Inbound: extend webhook decoder to parse Like/Dislike events (Talk 21+) into NextcloudTalkInboundReaction; route through onReaction callback in monitorNextcloudTalkProvider; add handleNextcloudTalkInboundReaction stub (TODO: full dispatch on a future pass) - Types: extend NextcloudTalkWebhookPayload with Like/Dislike types and optional content field; add NextcloudTalkInboundReaction type - SDK: export jsonResult, readReactionParams, readStringParam from plugin-sdk/nextcloud-talk surface - Tests: channel-actions.test.ts (2 tests), monitor.reaction.test.ts (3 tests) — all 73 nextcloud-talk tests pass
Adds an optional `ackReaction` config field (account- and room-level). When set, the bot sends a reaction emoji to every received message that passes all gate checks (best-effort; errors are logged, not thrown). Room-level `ackReaction` takes precedence over account-level. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…c ackReaction field
Implements typing indicator signaling so the bot shows a 'composing'
status while processing a message.
- Add NextcloudTalkTypingIndicator type and typingIndicator config option
to NextcloudTalkRoomConfig and NextcloudTalkAccountConfig
- Add send-typing.ts: sendTypingNextcloudTalk() using the proposed bot
typing endpoint POST /ocs/v2.php/apps/spreed/api/v1/bot/{token}/typing
with HMAC-SHA256 auth (same pattern as sendMessageNextcloudTalk)
- Gracefully handles 404 (endpoint not yet available on server) with a
one-time console.warn and continues without throwing
- Add resolveTypingIndicatorEnabled() for room-level override of
account-level setting (room config takes precedence)
- Integrate into inbound.ts: typing=true before dispatch, typing=false
after delivery or on dispatch error (fire-and-forget, non-blocking)
- Add config-schema.ts entries for typingIndicator on both room and
account schemas
- Add 16 unit tests covering valid/error paths and config resolution
Feature is opt-in: typingIndicator defaults to false. Enable per-account
or override per-room with typingIndicator: true/false.
b8a08c3 to
aa2a646
Compare
Summary
{mentionN}placeholders) and extract explicit mention entries for reliable mention detectionLike/Dislikewebhooks are decoded, access-checked, and forwarded to the agent as[Reaction]messagesresolveAckReaction(channel/account/global hierarchy + room-level override)POST /bot/{token}/typing, opt-in per account or roomfetchWithSsrFGuard+ssrfPolicyFromPrivateNetworkOptInFixes included
send-typing.ts)monitor-runtime.ts)handleNextcloudTalkInboundReactionhonorsdmPolicy: openfor direct-room reactionsackReactionconfig is now consulted before the channel/account hierarchyTest plan
pnpm test extensions/nextcloud-talk— 17 files, all passpnpm tsgo:prod— no errors🤖 Generated with Claude Code