Skip to content

fix(slack): per-thread session keys to prevent context mixing#17908

Closed
tonydehnke wants to merge 5 commits intoopenclaw:mainfrom
tonydehnke:fix/slack-thread-level-sessions
Closed

fix(slack): per-thread session keys to prevent context mixing#17908
tonydehnke wants to merge 5 commits intoopenclaw:mainfrom
tonydehnke:fix/slack-thread-level-sessions

Conversation

@tonydehnke
Copy link
Contributor

@tonydehnke tonydehnke commented Feb 16, 2026

Summary

Rebased and extended version of #10686 by @pablohrcarvalho, updated to current main with the previousTimestamp fix from Greptile's review.

  • Per-thread session keys for channels/groups — each Slack thread gets its own session, preventing cross-thread context contamination
  • Increased thread cache TTL from 60s to 6hrs and max entries from 500 to 10k — users often pause conversations for hours
  • Thread-level system event session keysresolveSlackSystemEventSessionKey now accepts threadTs/messageTs for forward-compatible thread isolation of system events
  • DM thread session preservation — DM thread replies get thread-level sessions (matching channel behavior), while non-threaded DMs keep the base session key
  • previousTimestamp fix (Greptile review) — reads from the resolved thread-level sessionKey instead of route.sessionKey, so the elapsed-time envelope header uses the correct per-thread timestamp

Changes

File Change
src/slack/monitor/message-handler/prepare.ts canonicalThreadId for thread-level session routing + previousTimestamp fix
src/slack/monitor/thread-resolution.ts Cache TTL 60s→6hrs, max 500→10k
src/slack/monitor/context.ts resolveSlackSystemEventSessionKey accepts threadTs/messageTs
src/slack/monitor/message-handler/prepare.thread-session-key.test.ts Regression test for previousTimestamp (3 cases: channel, thread reply, DM)

Production evidence

We've been running these fixes as local bundle patches since v2026.2.9 (~2 weeks). Before the fix, ~10% of channel threads experienced session splitting or cross-contamination. After the fix: zero incidents.

Test plan

  • All 149 Slack tests pass (17 test files)
  • Full suite: 762 test files, 6646 tests, 0 failures
  • pnpm build clean
  • pnpm check (oxlint + oxfmt) clean
  • Regression test verifies readSessionUpdatedAt uses thread-level key (fails without fix, passes with)

Co-authored-by: pablohrcarvalho pablohrcarvalho@users.noreply.github.com

Supersedes #10686
Closes #758
Related: #12389, #4927, #7610

Greptile Summary

This PR implements per-thread session isolation for Slack to prevent context mixing between threads. The implementation correctly distinguishes between channels/groups (where every message gets its own thread-level session) and DMs (where only actual thread replies get thread-level sessions).

Key changes:

  • prepare.ts:207-211 introduces canonicalThreadId logic that uses message.ts as the thread ID for top-level channel messages, ensuring each channel message starts its own session context
  • prepare.ts:429 fixes the previousTimestamp bug by reading from the resolved thread-level sessionKey instead of route.sessionKey, ensuring elapsed-time envelope headers reflect per-thread timestamps
  • thread-resolution.ts:13-14 increases cache TTL from 60s to 6 hours and max entries from 500 to 10k to better support real-world usage patterns
  • context.ts:177-209 adds optional threadTs/messageTs parameters to resolveSlackSystemEventSessionKey for forward-compatible thread isolation of system events (currently not used by existing callers)

Test coverage:
The new test file validates the core fix with three scenarios: channel messages, thread replies, and DMs. The tests spy on readSessionUpdatedAt calls to verify the correct session key is used for reading previousTimestamp.

Production validation:
Per the PR description, these fixes have been running in production as bundle patches for ~2 weeks with zero incidents after previously experiencing ~10% thread contamination.

Confidence Score: 5/5

  • This PR is safe to merge with high confidence
  • The implementation is well-designed with clear logic separation between channel and DM threading behavior, includes comprehensive test coverage for the core fix, has been validated in production for 2 weeks, and all 762 test files pass cleanly
  • No files require special attention

Last reviewed commit: d9bc772

pablomarchant and others added 5 commits February 16, 2026 07:13
… mixing

## Problem

All messages in a Slack channel share a single session, causing context from
different threads to mix together. When users have multiple conversations in
different threads of the same channel, the agent sees combined context from
all threads, leading to confused responses.

Session key was: `slack:channel:${channelId}` (no thread identifier)

## Solution

1. **Thread-level session keys**: Each message in channels/groups now gets
   its own session based on thread_ts:
   - Thread replies: use the parent thread's ts
   - New messages: use the message's own ts (becomes thread root)
   - DMs: unchanged (no thread-level sessions needed)

   New session key format: `slack:channel:${channelId}:thread:${threadTs}`

2. **Increased thread cache TTL**: Changed from 60 seconds to 6 hours.
   Users often pause conversations, and the short TTL caused unnecessary
   API calls and thread resolution failures.

3. **Increased cache size**: Changed from 500 to 10,000 entries to support
   busy workspaces with many active threads.

## Testing

1. Create two threads in the same Slack channel
2. In Thread A: tell the bot your name is "Alice" and ask about "billing"
3. In Thread B: tell the bot your name is "Bob" and ask about "API"
4. Reply in Thread A and ask "what's my name?" - should say "Alice"
5. Check sessions: each thread should have a unique session key with :thread: suffix

Fixes context bleed issues related to openclaw#758
…level sessions

The context.ts file has a separate function for resolving session keys for
system events (reactions, file uploads, etc.). This also needs to support
thread-level sessions to ensure all Slack events route to the correct
thread-specific session.

Added threadTs and messageTs parameters to resolveSlackSystemEventSessionKey
and updated the implementation to use thread-level keys for channels/groups.
The previous change broke thread-level sessions for DMs that have threads.
DMs with parent_user_id should still get thread-level sessions.

- For channels/groups: always use thread-level sessions
- For DMs: use thread-level sessions only when isThreadReply is true
Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

4 files reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Feb 16, 2026

Additional Comments (1)

src/slack/monitor/context.ts
added threadTs/messageTs for forward-compatible thread isolation - current callers in events/ (reactions, edits, pins, members) don't pass thread info yet, so system events still use base channel sessions

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/slack/monitor/context.ts
Line: 177:209

Comment:
added `threadTs`/`messageTs` for forward-compatible thread isolation - current callers in `events/` (reactions, edits, pins, members) don't pass thread info yet, so system events still use base channel sessions

How can I resolve this? If you propose a fix, please make it concise.

@sebslight
Copy link
Member

Closing as duplicate of #10686. If this is incorrect, please contact us.

@sebslight sebslight closed this Feb 20, 2026
@pablohrcarvalho
Copy link
Contributor

@sebslight @tonydehnke

I have added all the changes and fixes @tonydehnke requested in PR #10686. Also, I added @tonydehnke as a co-author. Thank you for reviewing and improving this @tonydehnke.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

channel: slack Channel integration: slack size: M

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Slack thread sessions have unpredictable context inheritance/bleed

5 participants