Skip to content

fix(slack): refresh thread context for investigations - #62299

Closed
oferlaor wants to merge 1 commit into
NousResearch:mainfrom
oferlaor:fix/slack-investigate-thread-context
Closed

fix(slack): refresh thread context for investigations#62299
oferlaor wants to merge 1 commit into
NousResearch:mainfrom
oferlaor:fix/slack-investigate-thread-context

Conversation

@oferlaor

@oferlaor oferlaor commented Jul 10, 2026

Copy link
Copy Markdown

Summary

  • Re-fetches and prepends Slack thread context for explicit investigate, investigate ..., and investigate: ... thread replies even when a Hermes session already exists.
  • Avoids duplicate hydration when the incoming message already contains the thread-context marker.
  • Preserves current workspace-scoped Slack thread/session keys and the current plugin architecture.
  • Adds focused regression coverage for forced hydration and duplicate suppression.

Root cause

Slack thread context is normally fetched only when entering a thread with no active Hermes session. If an earlier empty or interrupted turn created the session without useful context, a later investigate request skipped _fetch_thread_context() and the agent missed the parent alert/request.

This keeps normal thread messages unchanged and refreshes context only for explicit investigation triggers.

Supersedes closed #23141 with a current-main port to plugins/platforms/slack/adapter.py.

Validation

  • scripts/run_tests.sh tests/gateway/test_slack.py tests/gateway/test_slack_channel_session_scope.py tests/gateway/test_slack_mention.py -q329 passed
  • .venv/bin/ruff check plugins/platforms/slack/adapter.py tests/gateway/test_slack.py → passed
  • git diff --check origin/main...HEAD → passed

Current status

Rebased onto current main (d7b36070ef807841699ad32c5b6af547fee3ff64) on 2026-07-20 while preserving newer workspace-scoped Slack thread state. No unresolved review threads at refresh time.

@oferlaor

oferlaor commented Jul 10, 2026

Copy link
Copy Markdown
Author

Refreshed onto current main at 5141453975a6560a4b75f1e20887551b4fa6589f, scoped only to the still-missing investigation-context invariant in the extracted Slack plugin adapter. Focused Slack tests: 329 passed; Ruff and diff checks clean. CI run is awaiting maintainer approval: https://github.com/NousResearch/hermes-agent/actions/runs/29776785385

@alt-glitch alt-glitch added type/bug Something isn't working comp/plugins Plugin system and bundled plugins platform/slack Slack app adapter P3 Low — cosmetic, nice to have labels Jul 10, 2026
@teknium1 teknium1 added sweeper:risk-session-state Sweeper risk: may lose/corrupt/mis-associate session or context state sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform labels Jul 11, 2026
@oferlaor
oferlaor force-pushed the fix/slack-investigate-thread-context branch 2 times, most recently from c315edb to 58f8f37 Compare July 15, 2026 18:50
@oferlaor
oferlaor force-pushed the fix/slack-investigate-thread-context branch from 58f8f37 to 5141453 Compare July 20, 2026 20:35
teknium1 pushed a commit that referenced this pull request Jul 22, 2026
Once a thread has an active session, a later reply that explicitly
@mentions the bot did not re-fetch Slack thread context, so the agent
missed messages added to the thread after the initial hydrate (e.g.
other bots/integrations replying in multi-agent workflows). The
explicit mention is a fresh intent signal and now triggers a refresh.

Mechanics:
- SessionEntry gains a small persisted metadata dict, with
  SessionStore.get/set_session_metadata accessors (survives gateway
  restarts via the routing index).
- The adapter stores a per-thread consumption watermark
  (slack_thread_watermark:<channel>:<thread>) recording the last
  thread ts the session consumed.
- On explicit mention in an active thread, _fetch_thread_context runs
  with force_refresh=True (bypassing the TTL cache) and after_ts=<the
  watermark>, so only NOT-yet-seen messages are injected — as part of
  the new turn via channel_context. Prior conversation history is
  never rewritten, preserving prompt caching.
- _fetch_thread_context caches raw conversations.replies payloads so
  watermark-scoped re-formatting needs no extra API call; formatting
  is split into _format_thread_context.
- Thread session keys are built once in _build_thread_session_key
  (shared by the wake gate and the watermark accessors), still via
  build_session_key().

Fixes #23918. Supersedes #62299 (keyword-triggered refresh limited to
'investigate' prompts — the mention signal is the general fix).

Salvaged from #23927 by @heathley, rebased onto the plugin adapter
layout and rerouted through channel_context instead of text-prepend.
teknium1 pushed a commit that referenced this pull request Jul 22, 2026
Once a thread has an active session, a later reply that explicitly
@mentions the bot did not re-fetch Slack thread context, so the agent
missed messages added to the thread after the initial hydrate (e.g.
other bots/integrations replying in multi-agent workflows). The
explicit mention is a fresh intent signal and now triggers a refresh.

Mechanics:
- SessionEntry gains a small persisted metadata dict, with
  SessionStore.get/set_session_metadata accessors (survives gateway
  restarts via the routing index).
- The adapter stores a per-thread consumption watermark
  (slack_thread_watermark:<channel>:<thread>) recording the last
  thread ts the session consumed.
- On explicit mention in an active thread, _fetch_thread_context runs
  with force_refresh=True (bypassing the TTL cache) and after_ts=<the
  watermark>, so only NOT-yet-seen messages are injected — as part of
  the new turn via channel_context. Prior conversation history is
  never rewritten, preserving prompt caching.
- _fetch_thread_context caches raw conversations.replies payloads so
  watermark-scoped re-formatting needs no extra API call; formatting
  is split into _format_thread_context.
- Thread session keys are built once in _build_thread_session_key
  (shared by the wake gate and the watermark accessors), still via
  build_session_key().

Fixes #23918. Supersedes #62299 (keyword-triggered refresh limited to
'investigate' prompts — the mention signal is the general fix).

Salvaged from #23927 by @heathley, rebased onto the plugin adapter
layout and rerouted through channel_context instead of text-prepend.
@teknium1

Copy link
Copy Markdown
Contributor

Closing as superseded by #69320 (merged): keyword-triggered ('investigate') refresh was narrower than the explicit-mention watermark-delta refresh that landed; the general mechanism covers your use case.

Thanks for digging into this — the consolidated fix stands on the cluster's collective analysis, and your work is credited in #69320's summary.

@teknium1 teknium1 closed this Jul 22, 2026
randlee pushed a commit to randlee/hermes-agent that referenced this pull request Aug 11, 2026
Once a thread has an active session, a later reply that explicitly
@mentions the bot did not re-fetch Slack thread context, so the agent
missed messages added to the thread after the initial hydrate (e.g.
other bots/integrations replying in multi-agent workflows). The
explicit mention is a fresh intent signal and now triggers a refresh.

Mechanics:
- SessionEntry gains a small persisted metadata dict, with
  SessionStore.get/set_session_metadata accessors (survives gateway
  restarts via the routing index).
- The adapter stores a per-thread consumption watermark
  (slack_thread_watermark:<channel>:<thread>) recording the last
  thread ts the session consumed.
- On explicit mention in an active thread, _fetch_thread_context runs
  with force_refresh=True (bypassing the TTL cache) and after_ts=<the
  watermark>, so only NOT-yet-seen messages are injected — as part of
  the new turn via channel_context. Prior conversation history is
  never rewritten, preserving prompt caching.
- _fetch_thread_context caches raw conversations.replies payloads so
  watermark-scoped re-formatting needs no extra API call; formatting
  is split into _format_thread_context.
- Thread session keys are built once in _build_thread_session_key
  (shared by the wake gate and the watermark accessors), still via
  build_session_key().

Fixes NousResearch#23918. Supersedes NousResearch#62299 (keyword-triggered refresh limited to
'investigate' prompts — the mention signal is the general fix).

Salvaged from NousResearch#23927 by @heathley, rebased onto the plugin adapter
layout and rerouted through channel_context instead of text-prepend.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/plugins Plugin system and bundled plugins P3 Low — cosmetic, nice to have platform/slack Slack app adapter sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:risk-session-state Sweeper risk: may lose/corrupt/mis-associate session or context state type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants