Skip to content

feat(slack): include thread metadata in agent context#6534

Closed
bennewton999 wants to merge 41 commits intoopenclaw:mainfrom
bennewton999:fix/slack-thread-metadata
Closed

feat(slack): include thread metadata in agent context#6534
bennewton999 wants to merge 41 commits intoopenclaw:mainfrom
bennewton999:fix/slack-thread-metadata

Conversation

@bennewton999
Copy link
Contributor

@bennewton999 bennewton999 commented Feb 1, 2026

Summary

Adds thread metadata (thread_ts and parent_user_id) to the message context passed to agents, enabling them to detect and respond to Slack threaded replies with context awareness.

Problem

Agents currently cannot determine if a Slack message is a threaded reply because OpenClaw receives but doesn't expose thread metadata from the Slack API.

Before:

[slack message id: 1769970942.286059 channel: C0ACKPWN3Q9]

After:

[slack message id: 1769970942.286059 channel: C0ACKPWN3Q9 thread_ts: 1769970000.123456 parent_user: U026H3AP1]

Changes

  • Modified src/slack/monitor/message-handler/prepare.ts to include thread metadata in message context
  • Thread replies include both thread_ts and parent_user_id (when available)
  • Thread starters include thread_ts only (they ARE the parent, not a reply)
  • Added comprehensive test coverage in prepare.inbound-contract.test.ts

Testing

  • ✅ All existing tests pass
  • ✅ Added 2 new tests for thread metadata:
    • Thread replies with parent_user_id present
    • Thread replies without parent_user_id
pnpm test src/slack/monitor/message-handler/prepare.inbound-contract.test.ts
# ✓ 4/4 tests passed

Use Cases Enabled

  • Agents can reference original context when replying in threads
  • Tools can fetch and analyze thread history
  • Distinguish new topics from thread continuations
  • Better conversation flow understanding

Breaking Changes

None - this is additive metadata only.

Closes #6531

Greptile Overview

Greptile Summary

This PR augments the Slack inbound message formatting to append thread metadata (thread_ts and optional parent_user_id) into the message footer that’s embedded in the agent-visible context, and adds contract tests to assert the metadata appears for thread replies.

The change is localized to the Slack monitor message preparation pipeline (src/slack/monitor/message-handler/prepare.ts), which is responsible for shaping the finalized MsgContext payload passed into agent execution and session/history logic. The new tests (prepare.inbound-contract.test.ts) cover presence/absence of parent_user_id in the emitted Body string.

Confidence Score: 4/5

  • This PR is likely safe to merge, with a small but real correctness issue in how thread_ts is computed for the thread starter envelope.
  • Changes are small and covered by new tests, but the thread starter metadata currently uses starter.ts instead of the known thread root timestamp and can omit thread_ts when starter.ts is missing, which undermines the feature’s stated contract for some thread-reply scenarios.
  • src/slack/monitor/message-handler/prepare.ts

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

…gent context

- Add thread_ts and parent_user_id to message metadata passed to agents
- Enables agents to detect threaded replies and provide context-aware responses
- Thread starters include thread_ts but not parent_user (they ARE the parent)
- Includes comprehensive test coverage for both cases

Fixes: Agents could not determine if Slack messages were thread replies
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.

2 files reviewed, 2 comments

Edit Code Review Agent Settings | Greptile

Comment on lines 470 to 472
// For thread starters, include thread_ts but not parent_user (the starter IS the parent)
const starterThreadInfo = starter.ts ? ` thread_ts: ${starter.ts}` : "";
const starterWithId = `${starter.text}\n[slack message id: ${starter.ts ?? threadTs} channel: ${message.channel}${starterThreadInfo}]`;
Copy link
Contributor

Choose a reason for hiding this comment

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

[P1] Thread starter metadata uses the wrong timestamp

In the thread-starter envelope you’re building starterThreadInfo from starter.ts, but thread_ts should be the thread root timestamp (threadTs), not the root message’s ts (though they’re often equal). If starter.ts is missing, this currently omits thread_ts entirely even though threadTs is known, and if starter.ts differs it will mislabel the thread. This affects only thread replies where resolveSlackThreadStarter returns a starter with text.

Also, the comment says “include thread_ts” but the code only includes it when starter.ts is present.

Suggested fix: use threadTs (or starter.ts ?? threadTs) for thread_ts in the starter envelope.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/slack/monitor/message-handler/prepare.ts
Line: 470:472

Comment:
[P1] Thread starter metadata uses the wrong timestamp

In the thread-starter envelope you’re building `starterThreadInfo` from `starter.ts`, but `thread_ts` should be the thread root timestamp (`threadTs`), not the root message’s `ts` (though they’re often equal). If `starter.ts` is missing, this currently omits `thread_ts` entirely even though `threadTs` is known, and if `starter.ts` differs it will mislabel the thread. This affects only thread replies where `resolveSlackThreadStarter` returns a starter with `text`.

Also, the comment says “include thread_ts” but the code only includes it when `starter.ts` is present.

Suggested fix: use `threadTs` (or `starter.ts ?? threadTs`) for `thread_ts` in the starter envelope.

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

Copy link
Contributor Author

Choose a reason for hiding this comment

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

✅ Fixed in 9ac4602 - now using threadTs instead of starter.ts for thread_ts metadata

Comment on lines +148 to +152
it("includes thread_ts and parent_user_id metadata in thread replies", async () => {
const slackCtx = createSlackMonitorContext({
cfg: {
channels: { slack: { enabled: true } },
} as OpenClawConfig,
Copy link
Contributor

Choose a reason for hiding this comment

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

[P3] Test name doesn’t match scope

These tests assert that ctxPayload.Body contains the metadata, but they don’t verify it’s specifically in the [slack message id: ...] footer or that top-level messages don’t get thread_ts. Consider tightening assertions (e.g., match the footer line) or renaming the tests to reflect that they validate Body output rather than “thread replies” behavior beyond that.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/slack/monitor/message-handler/prepare.inbound-contract.test.ts
Line: 148:152

Comment:
[P3] Test name doesn’t match scope

These tests assert that `ctxPayload.Body` contains the metadata, but they don’t verify it’s specifically in the `[slack message id: ...]` footer or that top-level messages don’t get `thread_ts`. Consider tightening assertions (e.g., match the footer line) or renaming the tests to reflect that they validate `Body` output rather than “thread replies” behavior beyond that.

<sub>Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!</sub>

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

Copy link
Contributor Author

Choose a reason for hiding this comment

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

✅ Fixed in 9ac4602 - improved assertions to use regex matching exact footer format and added test for top-level messages

@openclaw-barnacle openclaw-barnacle bot added the channel: slack Channel integration: slack label Feb 1, 2026
…ions

- Use threadTs (thread root) instead of starter.ts for thread_ts in starter metadata
- Ensures thread_ts is always present when threadTs is known
- Improve test assertions to verify exact message footer format
- Add test to verify top-level messages exclude thread_ts

Addresses code review feedback from greptile-apps
@bennewton999
Copy link
Contributor Author

Thanks for the review @greptile-apps! I've addressed both issues:

P1 - Thread starter timestamp: Fixed to use threadTs instead of starter.ts for the thread_ts metadata. This ensures the thread root timestamp is always used and the metadata is present whenever threadTs is known.

P3 - Test assertions: Improved test specificity:

  • Changed from .toContain() to .toMatch() with regex to verify exact message footer format
  • Added a new test to verify top-level messages explicitly exclude thread_ts
  • All 5 tests now passing ✓

Commit: 9ac4602

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Feb 1, 2026

Perfect! I can see both fixes have been implemented correctly:

✅ P1 Fix - Thread starter timestamp:
Your fix in prepare.ts now uses threadTs instead of starter.ts, ensuring consistent thread root timestamps and guaranteed presence of thread_ts metadata when available.

✅ P3 Fix - Test assertions:
The test improvements in prepare.inbound-contract.test.ts show much better specificity:

  • Switched to regex-based assertions with .toMatch() for exact format verification
  • Added coverage for top-level messages excluding thread_ts
  • Expanded from 3 to 5 tests with comprehensive thread scenarios

The commit stats (+81/-5 lines) reflect the substantial test improvements while keeping the core logic change minimal (just 2 lines changed in prepare.ts).

Both issues are now properly addressed. The thread metadata feature should work reliably across all Slack thread scenarios, and the tests provide robust verification of the expected message footer formats.

@openclaw-barnacle openclaw-barnacle bot added docs Improvements or additions to documentation channel: telegram Channel integration: telegram docker Docker and sandbox tooling labels Feb 1, 2026
alexanderatallah and others added 20 commits February 1, 2026 19:06
* docs(discord): clarify exec approvals UI

* Add link for slash command in Discord exec approvals

Updated documentation to include a link for the slash command used in Discord exec approvals.

* docs(discord): move exec approvals note

* docs(discord): document exec approvals config

* docs(discord): reorder exec approvals config

---------

Co-authored-by: Luke K (pr-0f3t) <[email protected]>
- Fix @1 -> $1 in landpr.md
- Fix $@ -> $1 in reviewpr.md
- Remove stray /reviewpr line from reviewpr.md
- Delete old pr.md (replaced by reviewpr.md and landpr.md)
* improve exe.dev setup instructions

1. Fix device approval command
2. Clarify where Gateway token can be found

* Update device approval instructions in exe-dev.md

Clarify instructions for approving devices in OpenClaw.
…penclaw#6398)

* security(message-tool): validate filePath/path against sandbox root

* style: translate Polish comments to English for consistency
…penclaw#4610)

* security(web): sanitize WhatsApp accountId to prevent path traversal

Apply normalizeAccountId() from routing/session-key to
resolveDefaultAuthDir() so that malicious config values like
"../../../etc" cannot escape the intended auth directory.

Fixes openclaw#2692

* fix(web): check sanitized segment instead of full path in Windows test

* style(web): fix oxfmt formatting in accounts test
hclsys and others added 3 commits February 1, 2026 19:06
…5926)

Add timeout protection to prevent indefinite hangs when Urbit server
becomes unresponsive or network partition occurs.

Changes:
- Add AbortSignal.timeout(30_000) to 7 one-shot fetch calls
- Add AbortController with 60s connection timeout to SSE stream fetch
  (clears timeout after headers received to avoid aborting active stream)

Affected methods: sendSubscription, connect, openStream, poke, scry, close

Fixes openclaw#5266

Co-authored-by: Claude Opus 4.5 <[email protected]>
@bennewton999
Copy link
Contributor Author

✅ Merged latest main and resolved conflicts.

  • Rebased on upstream/main (36 commits)
  • All 5 tests still passing
  • Build successful
  • Ready for review

@openclaw-barnacle openclaw-barnacle bot added channel: discord Channel integration: discord channel: googlechat Channel integration: googlechat channel: line Channel integration: line channel: tlon Channel integration: tlon channel: whatsapp-web Channel integration: whatsapp-web app: web-ui App: web-ui commands Command implementations agents Agent runtime and tooling labels Feb 2, 2026
@openclaw-barnacle openclaw-barnacle bot removed docs Improvements or additions to documentation channel: discord Channel integration: discord channel: googlechat Channel integration: googlechat channel: line Channel integration: line channel: telegram Channel integration: telegram channel: tlon Channel integration: tlon channel: whatsapp-web Channel integration: whatsapp-web app: web-ui App: web-ui commands Command implementations docker Docker and sandbox tooling labels Feb 2, 2026
@bennewton999
Copy link
Contributor Author

Closing in favor of #14625 — clean rebase on latest main with the same feature, minus the accumulated merge noise from this branch.

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

Labels

agents Agent runtime and tooling channel: slack Channel integration: slack

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Slack thread metadata (thread_ts, parent_user_id) missing in agent context

Comments