Skip to content

fix: handle string thread IDs in queue drain for Slack#4749

Closed
nvonpentz wants to merge 1 commit intoopenclaw:mainfrom
nvonpentz:fix/slack-thread-id-type-check
Closed

fix: handle string thread IDs in queue drain for Slack#4749
nvonpentz wants to merge 1 commit intoopenclaw:mainfrom
nvonpentz:fix/slack-thread-id-type-check

Conversation

@nvonpentz
Copy link
Copy Markdown

@nvonpentz nvonpentz commented Jan 30, 2026

Problem

When multiple messages arrive while the agent is busy (queued messages), replies to Slack threads were incorrectly being sent to the main channel instead of the thread.

Root Cause

The code in src/auto-reply/reply/queue/drain.ts checks for thread IDs using:

typeof threadId === "number"

However, Slack thread timestamps are strings (e.g., "1769015989.090599"), not numbers. This caused:

  1. Thread IDs to be filtered out when checking for cross-channel routing
  2. originatingThreadId to be undefined when collecting queued messages
  3. Replies going to the main channel instead of the originating thread

Fix

Changed type checks from typeof threadId === "number" to threadId != null which correctly handles both string (Slack) and number thread IDs across different providers.

Testing

Tested locally by:

  1. Sending multiple messages in a Slack thread while agent was busy
  2. Verified replies now correctly go to the thread instead of main channel

Greptile Overview

Greptile Summary

This PR fixes followup queue drain routing when draining queued messages for Slack threads. The prior logic treated originatingThreadId as numeric-only (typeof ... === "number"), but Slack thread timestamps are strings, so the thread component was dropped during cross-channel key generation and while selecting an originatingThreadId for collect mode.

The change switches thread detection to null checks (threadId != null) so both string and number thread IDs are preserved in the routing key and in the collected followup run, keeping replies routed to the original thread instead of the main channel.

Confidence Score: 4/5

  • This PR is safe to merge with low risk; it’s a narrow fix to thread ID handling in queue drain routing.
  • The change is small and localized (replacing numeric-only thread checks with null checks) and aligns with Slack’s thread timestamp format. Primary remaining risk is limited test coverage for string thread IDs in collect routing, since the existing routing test helper constrains thread IDs to number and doesn’t exercise the Slack case.
  • src/auto-reply/reply/queue/drain.ts; consider extending src/auto-reply/reply/queue.collect-routing.test.ts to cover string thread IDs

(2/5) Greptile learns from your feedback when you react with thumbs up/down!

Slack thread timestamps are strings (e.g., '1769015989.090599'), not numbers.
The type check `typeof threadId === 'number'` caused thread IDs to be
dropped when collecting queued messages, resulting in replies going to
the main channel instead of the thread.

Changed to use null checks (`!= null`) which correctly handles both
string and number thread IDs across different providers.
Copy link
Copy Markdown
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.

1 file reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

Comment on lines 72 to 76
(i) => i.originatingAccountId,
)?.originatingAccountId;
const originatingThreadId = items.find(
(i) => typeof i.originatingThreadId === "number",
(i) => i.originatingThreadId != null,
)?.originatingThreadId;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[P2] Collect-routing test type mismatch

FollowupRun.originatingThreadId is string | number (src/auto-reply/reply/queue/types.ts:40-41), and this PR explicitly targets Slack’s string thread timestamps, but createRun in src/auto-reply/reply/queue.collect-routing.test.ts currently types originatingThreadId?: number (line 13). This makes it easy to miss regressions involving string thread IDs in collect routing/drain behavior.

Consider widening the test helper type and adding at least one case that sets a string thread id.

Also appears in: src/auto-reply/reply/queue.collect-routing.test.ts:7-14

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/auto-reply/reply/queue/drain.ts
Line: 72:76

Comment:
[P2] Collect-routing test type mismatch

`FollowupRun.originatingThreadId` is `string | number` (`src/auto-reply/reply/queue/types.ts:40-41`), and this PR explicitly targets Slack’s string thread timestamps, but `createRun` in `src/auto-reply/reply/queue.collect-routing.test.ts` currently types `originatingThreadId?: number` (line 13). This makes it easy to miss regressions involving string thread IDs in collect routing/drain behavior.

Consider widening the test helper type and adding at least one case that sets a string thread id.

Also appears in: `src/auto-reply/reply/queue.collect-routing.test.ts:7-14`

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

@Lukavyi
Copy link
Copy Markdown
Contributor

Lukavyi commented Feb 7, 2026

Hey! I ran into the same issue and submitted #11194 which builds on this approach but adds empty-string edge case protection (threadId != null && threadId !== "" instead of just threadId == null). This addresses the concern Greptile raised in the review here — if any provider normalizes missing thread IDs to "", the != null check alone would treat it as a real thread. Also added 3 test cases for string thread_ts handling.

@steipete
Copy link
Copy Markdown
Contributor

AI-assisted stale triage closure (2026-02-24).

Closing this PR because the fix is already in main.

Why:

This is AI-closed housekeeping, not a rejection of the report.

If you still see Slack thread-id type issues, open a new focused PR from latest main with repro details.

@steipete steipete closed this Feb 24, 2026
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.

3 participants