fix(slack): reduce token bloat by skipping thread context on existing sessions#32133
Conversation
48420ad to
012d84e
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 012d84ec17
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| }); | ||
| if (threadInitialHistoryLimit > 0) { | ||
| // Only fetch thread history for NEW sessions (existing sessions already have this context in their transcript) | ||
| if (threadInitialHistoryLimit > 0 && !threadSessionPreviousTimestamp) { |
There was a problem hiding this comment.
Check thread session freshness before skipping context preload
This condition treats any existing store entry as an active thread session, but session reuse is actually gated by freshness in initSessionState (src/auto-reply/reply/session.ts:411-424) and stale entries are reset (default mode is daily in src/config/sessions/reset.ts:20-23). In the common case where a thread has an old updatedAt (or idle-expired entry), prepareSlackMessage now skips loading thread history/starter context even though a brand new agent session will be created, so the first message after reset loses prior thread context and can produce incorrect replies.
Useful? React with 👍 / 👎.
Greptile SummaryPrevents redundant thread context from being fetched and included on every message in a Slack thread, significantly reducing token bloat and API calls for multi-turn conversations. Key Changes:
Implementation:
Impact:
Confidence Score: 5/5
Last reviewed commit: 012d84e |
… sessions Thread history and thread starter were being fetched and included on every message in a Slack thread, causing unnecessary token bloat. The session transcript already contains the full conversation history, so re-fetching and re-injecting thread history on each turn is redundant. Now thread history is only fetched for new thread sessions (!threadSessionPreviousTimestamp). Existing sessions rely on their transcript for context. Fixes openclaw#32121
012d84e to
fc8f18e
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: fc8f18e02b
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| }); | ||
| if (threadInitialHistoryLimit > 0) { | ||
| // Only fetch thread history for NEW sessions (existing sessions already have this context in their transcript) | ||
| if (threadInitialHistoryLimit > 0 && !threadSessionPreviousTimestamp) { |
There was a problem hiding this comment.
Check session freshness before skipping thread context
The new gate threadInitialHistoryLimit > 0 && !threadSessionPreviousTimestamp treats any stored updatedAt as an active thread session, but session reuse is actually decided by freshness in initSessionState via evaluateSessionFreshness (src/auto-reply/reply/session.ts). Fresh evidence is that a stale entry (daily/idle reset) still has updatedAt, so this branch skips loading thread history (and the later starter-body assignment also skips starter text), even though the run will create a brand-new session; that makes the first post-reset thread message lose prior context and can produce incorrect replies.
Useful? React with 👍 / 👎.
…eload Previously, the fix only checked if a session timestamp existed, but didn't account for session freshness. A stale session (e.g., from yesterday before the daily reset hour) has a timestamp, so we skipped loading thread history, but initSessionState creates a brand new session because it's stale - causing the first message after reset to lose context. Now we check session freshness using the same logic as initSessionState: - Truly new session (no timestamp) → load thread history - Stale session (exists but expired) → load thread history (will be reset) - Fresh session (exists and active) → skip thread history (use transcript) Fixes comment on PR openclaw#32133
…eload Previously, the fix (openclaw#32133) only checked if a session timestamp existed, but didn't account for session freshness. A stale session (e.g., from yesterday before the daily reset hour) has a timestamp, so we skipped loading thread history, but initSessionState creates a brand new session because it's stale - causing the first message after reset to lose context. Now we check session freshness using the same logic as initSessionState: - Truly new session (no timestamp) → load thread history - Stale session (exists but expired) → load thread history (will be reset) - Fresh session (exists and active) → skip thread history (use transcript) Also fixes the wildcard bug in resolveChannelResetConfig so resetByChannel["*"] works as a catch-all for channel-specific session reset policies. Fixes comment on PR openclaw#32133
…eload Previously, the fix (openclaw#32133) only checked if a session timestamp existed, but didn't account for session freshness. A stale session (e.g., from yesterday before the daily reset hour) has a timestamp, so we skipped loading thread history, but initSessionState creates a brand new session because it's stale - causing the first message after reset to lose context. Now we check session freshness using the same logic as initSessionState: - Truly new session (no timestamp) → load thread history - Stale session (exists but expired) → load thread history (will be reset) - Fresh session (exists and active) → skip thread history (use transcript) Also fixes the wildcard bug in resolveChannelResetConfig so resetByChannel["*"] works as a catch-all for channel-specific session reset policies. Fixes comment on PR openclaw#32133
…eload Previously, the fix (openclaw#32133) only checked if a session timestamp existed, but didn't account for session freshness. A stale session (e.g., from yesterday before the daily reset hour) has a timestamp, so we skipped loading thread history, but initSessionState creates a brand new session because it's stale - causing the first message after reset to lose context. Now we check session freshness using the same logic as initSessionState: - Truly new session (no timestamp) → load thread history - Stale session (exists but expired) → load thread history (will be reset) - Fresh session (exists and active) → skip thread history (use transcript) Also fixes the wildcard bug in resolveChannelResetConfig so resetByChannel["*"] works as a catch-all for channel-specific session reset policies. Fixes comment on PR openclaw#32133
…eload Previously, the fix (openclaw#32133) only checked if a session timestamp existed, but didn't account for session freshness. A stale session (e.g., from yesterday before the daily reset hour) has a timestamp, so we skipped loading thread history, but initSessionState creates a brand new session because it's stale - causing the first message after reset to lose context. Now we check session freshness using the same logic as initSessionState: - Truly new session (no timestamp) → load thread history - Stale session (exists but expired) → load thread history (will be reset) - Fresh session (exists and active) → skip thread history (use transcript) Also fixes the wildcard bug in resolveChannelResetConfig so resetByChannel["*"] works as a catch-all for channel-specific session reset policies. Fixes comment on PR openclaw#32133
Previously, the fix (openclaw#32133) only checked if a session timestamp existed, but didn't account for session freshness. A stale session (e.g., from yesterday before the daily reset hour) has a timestamp, so we skipped loading thread history, but initSessionState creates a brand new session because it's stale - causing the first message after reset to lose context. Now we check session freshness using the same logic as initSessionState: - Truly new session (no timestamp) → load thread history - Stale session (exists but expired) → load thread history (will be reset) - Fresh session (exists and active) → skip thread history (use transcript) Also fixes the wildcard bug in resolveChannelResetConfig so resetByChannel["*"] works as a catch-all for channel-specific session reset policies. Fixes comment on PR openclaw#32133
Previously, the fix (openclaw#32133) only checked if a session timestamp existed, but didn't account for session freshness. A stale session (e.g., from yesterday before the daily reset hour) has a timestamp, so we skipped loading thread history, but initSessionState creates a brand new session because it's stale - causing the first message after reset to lose context. Now we check session freshness using the same logic as initSessionState: - Truly new session (no timestamp) → load thread history - Stale session (exists but expired) → load thread history (will be reset) - Fresh session (exists and active) → skip thread history (use transcript) Also fixes the wildcard bug in resolveChannelResetConfig so resetByChannel["*"] works as a catch-all for channel-specific session reset policies. Fixes comment on PR openclaw#32133
Summary
Thread history and thread starter were being fetched and included on every message in a Slack thread, causing unnecessary token bloat. The session transcript already contains the full conversation history, so re-fetching and re-injecting thread history on each turn is redundant.
What Changed
!threadSessionPreviousTimestamp)ThreadStarterBodyfor NEW sessionsBefore vs After
Before: Every message in a Slack thread included
[Thread history - for context]with the entire thread conversation, growing larger each turn.After: Thread history context wrapper is not needed since the agent has context form response. No further context is included
Session Evidence
Message 2 ("checking in"):
Message 3 ("what is the fifth letter in four"):
With this fix, messages do NOT include the redundant thread history wrapper.
Impact
Test Results
skips loading thread history when thread session already exists in store (bloat fix)to verify new behaviorFixes #32121