Skip to content

fix: restore chat message loading limits and preserve earlier messages#898

Merged
simple-agent-manager[bot] merged 5 commits intomainfrom
sam/fix-chat-message-loading-regression
May 5, 2026
Merged

fix: restore chat message loading limits and preserve earlier messages#898
simple-agent-manager[bot] merged 5 commits intomainfrom
sam/fix-chat-message-loading-regression

Conversation

@simple-agent-manager
Copy link
Copy Markdown
Contributor

Summary

Fixes two compounding regressions from PR #874:

  1. Message limit restored: getSessionMessageLimit() was using DEFAULT_SAM_HISTORY_LOAD_LIMIT (200) — a constant designed for SAM's own conversation persistence. Restored to a new DEFAULT_CHAT_SESSION_MESSAGE_LIMIT (3000), configurable via CHAT_SESSION_MESSAGE_LIMIT env var.

  2. Earlier messages preserved through polls: mergeReplace() was discarding all previously-loaded earlier messages on every 3-second poll cycle and WebSocket catch-up. Now preserves messages older than the incoming window, so "Load earlier messages" results persist.

  3. Same-timestamp boundary fix: Messages at the boundary timestamp that aren't in the incoming set (loaded via load-more) are preserved instead of silently dropped.

  4. onCatchUp interface cleaned: Removed unused hasMore parameter from the WebSocket catch-up callback contract.

Changes

  • packages/shared/src/constants/defaults.ts — new DEFAULT_CHAT_SESSION_MESSAGE_LIMIT (3000)
  • apps/api/src/routes/chat.ts — use new constant instead of SAM history limit
  • apps/web/src/lib/merge-messages.tsmergeReplace() preserves earlier-loaded messages
  • apps/web/src/components/project-message-view/useSessionLifecycle.ts — polling no longer resets hasMore
  • apps/web/src/hooks/useChatWebSocket.tsonCatchUp simplified to 2 params
  • Tests updated and added for all changes

Test plan

  • mergeReplace() preserves messages older than incoming window
  • Same-timestamp boundary messages from load-more are preserved
  • Empty catch-up does not wipe existing messages
  • getSessionMessageLimit() uses new 3000 default
  • All 2012 tests pass, typecheck clean, build succeeds
  • Staging deployed and verified — app loads, sessions display messages correctly

Staging Verification

  • Deployed via deploy-staging.yml (run succeeded 2026-05-05)
  • Authenticated via Playwright, navigated dashboard, projects, settings
  • Opened chat session with 55 messages — loaded and displayed correctly
  • No console errors related to the fix

Co-Authored-By: Claude Opus 4.6 [email protected]

raphaeltm and others added 5 commits May 5, 2026 06:27
Two regressions from PR #874 (May 1):

1. Message limit dropped from 1000 to 200 by reusing SAM_HISTORY_LOAD_LIMIT
   (designed for SAM conversation persistence) for chat session REST endpoints.
   Added DEFAULT_CHAT_SESSION_MESSAGE_LIMIT (3000) with CHAT_SESSION_MESSAGE_LIMIT
   env var override.

2. Polling fallback (every 3s) and WebSocket catch-up used 'replace' merge
   strategy that discarded all earlier-loaded messages. After clicking
   "Load earlier messages", the next poll cycle would reset back to 200.
   Fixed mergeReplace() to preserve messages older than the incoming window,
   and removed hasMore reset from polling/catch-up (only initial load and
   explicit loadMore should update pagination state).

Co-Authored-By: Claude Opus 4.6 <[email protected]>
- Fix extra closing brace in merge-messages.test.ts that caused parse error
- Update project-message-view catch-up test: empty incoming now correctly
  preserves existing messages (intentional behavior change from the fix)

Co-Authored-By: Claude Opus 4.6 <[email protected]>
- Move DEFAULT_CHAT_SESSION_MESSAGE_LIMIT from sam.ts to defaults.ts
  (it's a chat REST limit, not a SAM agent constant)
- Remove hasMore param from onCatchUp interface in useChatWebSocket.ts
  (catch-up should not reset pagination state)
- Update WorkspaceChatView.tsx onCatchUp to match new 2-param contract
- Update test mocks to match new interface

Co-Authored-By: Claude Opus 4.6 <[email protected]>
The mergeReplace boundary condition now preserves messages from prev
at the same timestamp as oldestIncoming when their ID is not in the
incoming set. This prevents silent drops when the server returns only
some messages at the boundary timestamp (e.g., batched tool calls).

Co-Authored-By: Claude Opus 4.6 <[email protected]>
@simple-agent-manager simple-agent-manager Bot merged commit 58cd4f1 into main May 5, 2026
10 of 13 checks passed
@sonarqubecloud
Copy link
Copy Markdown

sonarqubecloud Bot commented May 5, 2026

Quality Gate Failed Quality Gate failed

Failed conditions
14.3% Duplication on New Code (required ≤ 3%)

See analysis details on SonarQube Cloud

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.

1 participant