e5c7328cf5
After context compression in an active conversation, scrolling to the top
would not load earlier messages because useThreadRuns was never invalidated
once new runs completed. The stale runs list left hasMore permanently false.
- Invalidate the ["thread", threadId] query in onFinish so the runs list
stays current as new runs are created
- Split the useThreadHistory effect into separate reset (threadId change)
and incremental-update (runs.data change) paths so indexRef is adjusted
without resetting already-loaded history
- Add message deduplication when prepending loaded run messages to guard
against overlap with the live stream
- Extract deduplicateHistoryMessages and adjustHistoryIndex into a pure
utility module with 10 unit tests
Closes #2965