Commit Graph

417 Commits

Author SHA1 Message Date
Glucksberg
6dbbc58a8d fix(slack): use SLACK_USER_TOKEN when connecting to Slack (#28103)
* fix(slack): use SLACK_USER_TOKEN when connecting to Slack (closes #26480)

* test(slack): fix account fixture typing for user token source

---------

Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
2026-03-01 11:05:35 -06:00
dan bachelder
46da76e267 fix(slack): honor replyToModeByChatType when ThreadLabel exists (#26251)
* fix(slack): honor direct replyToMode when thread label exists

ThreadLabel is a session/conversation label, not a reliable indicator
of an actual Slack thread reply. Using it to force replyToMode="all"
overrides replyToModeByChatType.direct="off" in DMs.

Switch to MessageThreadId which indicates a real thread target is
available, preserving expected behavior: thread replies stay threaded,
normal DMs respect the configured mode.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Slack: add changelog for threading tool context fix

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
2026-03-01 11:02:06 -06:00
Dennis Rankin
a28a4b1b61 feat: detect stale Slack sockets and auto-restart (#30153)
* feat: detect stale Slack sockets and auto-restart

Slack Socket Mode connections can silently stop delivering events while
still appearing connected (health checks pass, WebSocket stays open).
This "half-dead socket" problem causes messages to go unanswered.

This commit adds two layers of protection:

1. **Event liveness tracking**: Every inbound Slack event (messages,
   reactions, member joins/leaves, channel events, pins) now calls
   `setStatus({ lastEventAt, lastInboundAt })` to update the channel
   account snapshot with the timestamp of the last received event.

2. **Health monitor stale socket detection**: The channel health monitor
   now checks `lastEventAt` against a configurable threshold (default
   30 minutes). If a channel has been running longer than the threshold
   and hasn't received any events in that window, it is flagged as
   unhealthy and automatically restarted — the same way disconnected
   or crashed channels are already handled.

The restart reason is logged as "stale-socket" for observability, and
the existing cooldown/rate-limit logic (3 restarts/hour max) prevents
restart storms.

* Slack: gate liveness tracking to accepted events

---------

Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
2026-03-01 10:58:21 -06:00
lailoo
43ddb41354 fix(slack): extract attachment text for bot messages with empty text (#27616) (#27642)
Verified:
- pnpm install --frozen-lockfile
- pnpm build
- pnpm check
- pnpm test:macmini
2026-03-01 10:49:51 -06:00
Miguel Miranda Dias
949faff5ce fix(slack): reconnect socket mode after disconnect (#27232)
* fix(slack): reconnect socket mode after disconnect

* fix(slack): avoid orphaned disconnect waiters on start failure

* docs(changelog): record slack socket reconnect reliability fix

---------

Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
2026-03-01 10:42:45 -06:00
Luis Conde
bd78a74298 feat(slack): track thread participation for auto-reply without @mention (#29165)
* feat(slack): track thread participation for auto-reply without @mention

* fix(slack): scope thread participation cache by accountId and capture actual reply thread ts

* fix(slack): capture reply thread ts from all delivery paths and only after success

* Slack: add changelog for thread participation cache behavior

---------

Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
2026-03-01 10:42:12 -06:00
Peter Machona
dfbdab5a29 fix(slack): map legacy streaming=false to off (openclaw#26020) thanks @chilu18
Verified:
- pnpm build
- pnpm check
- pnpm test:macmini

Co-authored-by: chilu18 <7957943+chilu18@users.noreply.github.com>
Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
2026-03-01 10:21:25 -06:00
dan bachelder
9ae94390b9 fix(slack): resolve replyToMode per-message using chat type (#24717)
* fix(slack): resolve replyToMode per-message using chat type

The Slack monitor resolved replyToMode once at startup from the
top-level config, ignoring replyToModeByChatType overrides. This caused
DM replies to be threaded even when replyToModeByChatType.direct was
set to "off".

Now the inbound message handler calls resolveSlackReplyToMode(account,
chatType) per-message — the same function already used by the outbound
dock and tool threading context — so per-chat-type overrides take
effect on the inbound path.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Slack: add changelog for per-message replyToMode resolution

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
2026-03-01 10:21:01 -06:00
Mark L
265b22c401 fix(slack): skip monitor startup for disabled accounts [AI-assisted] (openclaw#30592) thanks @liuxiaopai-ai
Verified:
- pnpm install --frozen-lockfile
- pnpm build
- pnpm check
- pnpm test:macmini

Co-authored-by: liuxiaopai-ai <73659136+liuxiaopai-ai@users.noreply.github.com>
Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
2026-03-01 10:19:50 -06:00
Colin Johnson
0f36ee5a2e Slack: harden slash and interactions ingress checks (openclaw#29091) thanks @Solvely-Colin
Verified:
- pnpm build
- pnpm check
- pnpm test:macmini

Co-authored-by: Solvely-Colin <211764741+Solvely-Colin@users.noreply.github.com>
Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
2026-03-01 09:40:57 -06:00
Glucksberg
3aad6c8bdb fix(slack): guard Socket Mode listeners access during startup (openclaw#28702) thanks @Glucksberg
Verified:
- pnpm install --frozen-lockfile
- pnpm build
- pnpm check
- pnpm test:macmini

Co-authored-by: Glucksberg <80581902+Glucksberg@users.noreply.github.com>
Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
2026-03-01 09:29:18 -06:00
HouRong
b3f60a68a0 fix(slack): thread agent identity through channel reply path (openclaw#27134) thanks @hou-rong
Verified:
- pnpm install --frozen-lockfile
- pnpm build
- pnpm check
- pnpm test:macmini

Co-authored-by: hou-rong <8758438+hou-rong@users.noreply.github.com>
Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
2026-03-01 09:25:32 -06:00
Peter Steinberger
8bc80fad47 fix(slack): land #29032 /agentstatus alias from @maloqab
Land contributor PR #29032 by @maloqab with Slack native alias docs, integration tests, and changelog entry.

Co-authored-by: maloqab <mitebaloqab@gmail.com>
2026-02-27 19:09:38 +00:00
Peter Steinberger
564be6b402 refactor(channels): unify dm pairing policy flows 2026-02-26 22:36:20 +01:00
Peter Steinberger
bce643a0bd refactor(security): enforce account-scoped pairing APIs 2026-02-26 21:57:52 +01:00
Peter Steinberger
d6eefe2e75 style: format auth boundary updates 2026-02-26 18:50:47 +01:00
Peter Steinberger
64de4b6d6a fix: enforce explicit group auth boundaries across channels 2026-02-26 18:49:16 +01:00
Peter Steinberger
cd80c7e7ff refactor: unify dm policy store reads and reason codes 2026-02-26 17:47:57 +01:00
SidQin-cyber
eb9a968336 fix(slack): suppress NO_REPLY before Slack API call
Guard sendMessageSlack against NO_REPLY tokens reaching the Slack API,
which caused truncated push notifications before the reply filter could
intercept them.

Made-with: Cursor
(cherry picked from commit fab9b5203965749e0fc72b58c4f42fbb3a1a18b8)
2026-02-26 13:40:58 +00:00
Peter Steinberger
3d30ba18a2 fix(slack): gate member and message subtype system events 2026-02-26 12:48:20 +01:00
Gustavo Madeira Santana
1ffc319831 Doctor: keep allowFrom account-scoped in multi-account configs 2026-02-26 05:34:58 -05:00
Peter Steinberger
e16e8f5af2 refactor(slack): share system-event ingress and test harness 2026-02-26 04:01:33 +01:00
Peter Steinberger
75dfb71e4e fix(slack): gate pin/reaction system events by sender auth 2026-02-26 03:48:58 +01:00
Peter Steinberger
069bbf9741 fix(slack): land #26878 allowlist channel ID case-insensitive match (thanks @lbo728)
Land contributor PR #26878 from @lbo728; include changelog credit and regression tests.

Co-authored-by: lbo728 <extreme0728@gmail.com>
2026-02-26 02:21:02 +00:00
Peter Steinberger
ce8c67c314 fix(slack): gate interactive system events by sender auth 2026-02-26 02:11:50 +01:00
Peter Steinberger
aedf62ac7e fix: harden discord and slack reaction ingress authorization 2026-02-26 01:26:47 +01:00
Peter Steinberger
b247cd6d65 fix: harden Slack file-only fallback placeholder (#25181) (thanks @justinhuangcode) 2026-02-25 05:36:49 +00:00
justinhuangcode
a6337be3d1 refactor: use MAX_SLACK_MEDIA_FILES constant for file-only fallback
Replace the hardcoded limit of 5 with the existing
MAX_SLACK_MEDIA_FILES constant (8) from media.ts for consistency.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 05:36:49 +00:00
justinhuangcode
def28a87b2 fix(slack): deliver file-only messages when all media downloads fail
When a Slack message contains only files/audio (no text) and every file
download fails, `resolveSlackMedia` returns null and `rawBody` becomes
empty, causing `prepareSlackMessage` to silently drop the message.

Build a fallback placeholder from the original file names so the agent
still receives the message, matching the pattern already used in
`resolveSlackThreadHistory` for file-only thread entries.

Closes #25064
2026-02-25 05:36:49 +00:00
Peter Steinberger
d42ef2ac62 refactor: consolidate typing lifecycle and queue policy 2026-02-25 02:16:03 +00:00
Peter Steinberger
e0201c2774 fix: keep channel typing active during long inference (#25886, thanks @stakeswky)
Co-authored-by: stakeswky <stakeswky@users.noreply.github.com>
2026-02-25 02:03:27 +00:00
Marcus Castro
3ff6e078ec test(slack): add missing allowNameMatching field to DM classification tests 2026-02-24 14:26:01 +00:00
Marcus Castro
f33d0a884e fix(slack): override wrong channel_type for D-prefix DM channels 2026-02-24 14:26:01 +00:00
Peter Steinberger
161d9841dc refactor(security): unify dangerous name matching handling 2026-02-24 01:33:08 +00:00
Peter Steinberger
f97c0922e1 fix(security): harden account-key handling against prototype pollution 2026-02-24 01:09:31 +00:00
Peter Steinberger
cfa44ea6b4 fix(security): make allowFrom id-only by default with dangerous name opt-in (#24907)
* fix(channels): default allowFrom to id-only; add dangerous name opt-in

* docs(security): align channel allowFrom docs with id-only default
2026-02-24 01:01:51 +00:00
Peter Steinberger
1c753ea786 test: dedupe fixtures and test harness setup 2026-02-23 05:45:54 +00:00
Peter Steinberger
86a8b65e9d test: consolidate redundant suites and speed up timers 2026-02-23 04:44:42 +00:00
Peter Steinberger
b534dfa3e0 fix(slack,web): harden thread hints and monitor tuning 2026-02-22 22:06:01 +00:00
Tak Hoffman
f8171ffcdc Config UI: tag filters and complete schema help/labels coverage (#23796)
* Config UI: add tag filters and complete schema help/labels

* Config UI: finalize tags/help polish and unblock test suite

* Protocol: regenerate Swift gateway models
2026-02-22 15:17:07 -06:00
Peter Steinberger
8af6d1a186 refactor(test): dedupe repeated fixture setup helpers 2026-02-22 20:04:51 +00:00
Vincent Koc
5e73f33448 fix(slack): keep thread session fork/history context after first turn (#23843)
* Slack thread sessions: keep forking and history context after first turn

* Update CHANGELOG.md
2026-02-22 14:39:00 -05:00
Vincent Koc
71c2c59c6c fix(slack): enforce replyToMode for auto-thread_ts and inline reply tags (#23839)
* Slack: respect replyToMode for auto-thread_ts and inline reply tags

* Update CHANGELOG.md
2026-02-22 14:36:46 -05:00
Peter Steinberger
0e4f3ccbdf refactor: dedupe media and request-body test scaffolding 2026-02-22 18:37:25 +00:00
Vincent Koc
89a1e99815 fix(slack): finalize replyToMode off threading behavior (#23799)
* fix: make replyToMode 'off' actually prevent threading in Slack

Three independent bugs caused Slack replies to always create threads
even when replyToMode was set to 'off':

1. Typing indicator created threads via statusThreadTs fallback (#16868)
   - resolveSlackThreadTargets fell back to messageTs for statusThreadTs
   - 'is typing...' was posted as thread reply, creating a thread
   - Fix: remove messageTs fallback, let statusThreadTs be undefined

2. [[reply_to_current]] tags bypassed replyToMode entirely (#16080)
   - Slack dock had allowExplicitReplyTagsWhenOff: true
   - Reply tags from system prompt always threaded regardless of config
   - Fix: set allowExplicitReplyTagsWhenOff to false for Slack

3. Contradictory replyToMode defaults in codebase (#20827)
   - monitor/provider.ts defaulted to 'all'
   - accounts.ts defaulted to 'off' (matching docs)
   - Fix: align provider.ts default to 'off' per documentation

Fixes: openclaw/openclaw#16868, openclaw/openclaw#16080, openclaw/openclaw#20827

* fix(slack): respect replyToMode in DMs even with typing indicator thread

When replyToMode is 'off' in DMs, replies should stay in the main
conversation even when the typing indicator creates a thread context.

Previously, when incomingThreadTs was set (from the typing indicator's
thread), replyToMode was forced to 'all', causing all replies to go
into the thread.

Now, for direct messages, the user's configured replyToMode is always
respected. For channels/groups, the existing behavior is preserved
(stay in thread if already in one).

This fix:
- Keeps the typing indicator working (statusThreadTs fallback preserved)
- Prevents DM replies from being forced into threads
- Maintains channel thread continuity

Fixes #16868

* refactor(slack): eliminate redundant resolveSlackThreadContext call

- Add isThreadReply to resolveSlackThreadTargets return value
- Remove duplicate call in dispatch.ts
- Addresses greptile review feedback with cleaner DRY approach

* docs(slack): add JSDoc to resolveSlackThreadTargets

Document return values including isThreadReply distinction between
genuine user thread replies vs bot status message thread context.

* docs(changelog): record Slack replyToMode off threading fixes

---------

Co-authored-by: James <jamesrp13@gmail.com>
Co-authored-by: theoseo <suhong.seo@gmail.com>
2026-02-22 13:27:50 -05:00
Vincent Koc
cd7b2814af fix(slack): preserve string thread context in queue + DM route (#23804)
* fix(slack): preserve thread_ts in queue drain and deliveryContext

Two related fixes for Slack thread reply routing:

1. Queue drain drops string thread_ts (#11195)
   - `typeof threadId === "number"` in drain.ts only matches Telegram numeric
     topic IDs. Slack thread_ts is a string like "1770474140.187459" which
     fails the check, causing threadKey to become empty.
   - Changed to `threadId != null && threadId !== ""` to accept both number
     and string thread IDs.
   - Applies to all 3 occurrences in drain.ts: cross-channel detection,
     thread key building, and collected originatingThreadId extraction.

2. DM deliveryContext missing thread_ts (#10837)
   - updateLastRoute calls for Slack DMs in both prepare.ts and dispatch.ts
     built deliveryContext without threadId, so the session's delivery context
     never included thread_ts for DM threads.
   - Added threadId from threadContext.messageThreadId / ctxPayload.MessageThreadId
     to both updateLastRoute call sites.

Tests: 3 new cases in queue.collect-routing.test.ts
- Collects messages with matching string thread_ts (same Slack thread)
- Separates messages with different string thread_ts (different threads)
- Treats empty string threadId same as absent

Closes #10837, closes #11195

* fix(slack): preserve string thread context in queue + DM route updates

---------

Co-authored-by: RobClawd <clawd@RobClawds-Mac-mini.local>
2026-02-22 13:26:31 -05:00
Luis Conde
af9881b9c5 fix(slack): resolve user IDs to DM channels before files.uploadV2 (#23773)
When a bare Slack user ID (U-prefix) is passed as the send target
without an explicit `user:` prefix, `parseSlackTarget` classifies it as
kind="channel".  `resolveChannelId` then passes it through to callers
without calling `conversations.open`.

This works for `chat.postMessage` (which tolerates user IDs), but
`files.uploadV2` delegates to `completeUploadExternal` which validates
`channel_id` against `^[CGDZ][A-Z0-9]{8,}$` — rejecting U-prefixed
IDs with `invalid_arguments`.

Fix: detect U-prefixed IDs in `resolveChannelId` regardless of the
parsed `kind`, and always resolve them via `conversations.open` to
obtain the DM channel ID (D-prefix).

Includes test coverage for bare, prefixed, and mention-style user ID
targets with file uploads, plus a channel-target negative case.
2026-02-22 13:04:53 -05:00
Peter Steinberger
296b19e413 test: dedupe gateway browser discord and channel coverage 2026-02-22 17:11:54 +00:00
Peter Steinberger
d116bcfb14 refactor(runtime): consolidate followup, gateway, and provider dedupe paths 2026-02-22 14:08:51 +00:00
Peter Steinberger
66f814a0af refactor(channels): dedupe plugin routing and channel helpers 2026-02-22 14:08:51 +00:00