[PR #1452] [CLOSED] fix(sdk): handle truncated history when root checkpoint missing #1468

Closed
opened 2026-02-15 20:15:52 -05:00 by yindo · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/langchain-ai/langgraphjs/pull/1452
Author: @ibbybuilds
Created: 7/26/2025
Status: Closed

Base: mainHead: fix/truncated-history-branch-tree


📝 Commits (3)

  • 15ace2b fix(sdk): handle truncated history when root checkpoint missing
  • 1adb0b8 chore(sdk): add changeset and fix formatting
  • 940285d fix(sdk): prevent incorrect message metadata with truncated history

📊 Changes

3 files changed (+116 additions, -20 deletions)

View changed files

.changeset/wide-memes-bake.md (+11 -0)
📝 libs/sdk/src/react/stream.tsx (+56 -20)
libs/sdk/src/tests/branchSequence.test.ts (+49 -0)

📄 Description

Problem

When using fetchStateHistory: { limit: N }, two critical issues occurred:

  1. Empty Branch Tree: The getBranchSequence function would return an empty branch tree, causing downstream consumers to receive an empty messages array. This happened because:

    • Limited history requests don't include the very first checkpoint (whose parent is null)
    • The algorithm looks for children of the synthetic root "$" but finds none
    • Result: empty rootSequence.items → empty history → empty messages array
  2. Incorrect Message Metadata: Messages beyond the loaded history window received incorrect metadata, allowing editing/regeneration from wrong checkpoints. This happened because:

    • findLastIndex would find messages in the oldest loaded state
    • Each LangGraph state contains the entire conversation history
    • Messages created before the loaded window appeared to be "created" in the oldest loaded state
    • Result: editing old messages would branch from incorrect checkpoints

Solution

Fix 1: Branch Tree Fallback

Added a fallback mechanism that detects "orphan" checkpoints - those whose parent isn't present in the truncated slice - and attaches them directly to the root.

Fix 2: Accurate Message Creation Detection

Replaced the flawed findLastIndex approach with findMessageCreationState function that:

  • Iterates through loaded history chronologically
  • Identifies the first state where a message appears that wasn't in the previous state
  • Returns undefined for messages that existed before the loaded window
  • Prevents editing/regeneration when parent checkpoint is unknown

Changes

src/react/stream.tsx

  • Exported getBranchSequence for testing
  • Added orphan-to-root fallback with clear documentation
  • Moved constants to fix linting issues
  • Implemented findMessageCreationState algorithm
  • Updated messageMetadata to use accurate creation state detection
  • Removed unused findLastIndex function

src/tests/branchSequence.test.ts

  • New unit test verifying truncated histories produce non-empty trees

Impact

  • Before: fetchStateHistory: { limit: 5 } → empty messages array + incorrect edit behavior
  • After: fetchStateHistory: { limit: 5 } → returns expected message list + safe editing only for messages with known parent checkpoints
  • No breaking changes - existing functionality unchanged
  • Patch release recommended

Testing

  • Build passes
  • All existing tests pass
  • New test covers the branch tree regression
  • Lint clean
  • Manual verification in production app
  • Edit/regenerate buttons properly hidden for messages without reliable parent checkpoints

Fixes empty message arrays and prevents incorrect branching when using fetchStateHistory limits.

Twitter/X handle: ibbyybuilds


🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/langchain-ai/langgraphjs/pull/1452 **Author:** [@ibbybuilds](https://github.com/ibbybuilds) **Created:** 7/26/2025 **Status:** ❌ Closed **Base:** `main` ← **Head:** `fix/truncated-history-branch-tree` --- ### 📝 Commits (3) - [`15ace2b`](https://github.com/langchain-ai/langgraphjs/commit/15ace2b5e9a90860149bef0e4765e91e5ec1a2e3) fix(sdk): handle truncated history when root checkpoint missing - [`1adb0b8`](https://github.com/langchain-ai/langgraphjs/commit/1adb0b812a88f9367b8d127ca94497ba57107238) chore(sdk): add changeset and fix formatting - [`940285d`](https://github.com/langchain-ai/langgraphjs/commit/940285dbdb9e068cc6120864f65b79d137539669) fix(sdk): prevent incorrect message metadata with truncated history ### 📊 Changes **3 files changed** (+116 additions, -20 deletions) <details> <summary>View changed files</summary> ➕ `.changeset/wide-memes-bake.md` (+11 -0) 📝 `libs/sdk/src/react/stream.tsx` (+56 -20) ➕ `libs/sdk/src/tests/branchSequence.test.ts` (+49 -0) </details> ### 📄 Description ## Problem When using `fetchStateHistory: { limit: N }`, two critical issues occurred: 1. **Empty Branch Tree**: The `getBranchSequence` function would return an empty branch tree, causing downstream consumers to receive an empty messages array. This happened because: - Limited history requests don't include the very first checkpoint (whose parent is `null`) - The algorithm looks for children of the synthetic root `"$"` but finds none - Result: empty `rootSequence.items` → empty `history` → empty `messages` array 2. **Incorrect Message Metadata**: Messages beyond the loaded history window received incorrect metadata, allowing editing/regeneration from wrong checkpoints. This happened because: - `findLastIndex` would find messages in the oldest loaded state - Each LangGraph state contains the entire conversation history - Messages created before the loaded window appeared to be "created" in the oldest loaded state - Result: editing old messages would branch from incorrect checkpoints ## Solution ### Fix 1: Branch Tree Fallback Added a fallback mechanism that detects "orphan" checkpoints - those whose parent isn't present in the truncated slice - and attaches them directly to the root. ### Fix 2: Accurate Message Creation Detection Replaced the flawed `findLastIndex` approach with `findMessageCreationState` function that: - Iterates through loaded history chronologically - Identifies the first state where a message appears that wasn't in the previous state - Returns `undefined` for messages that existed before the loaded window - Prevents editing/regeneration when parent checkpoint is unknown ## Changes ### `src/react/stream.tsx` - ✅ Exported `getBranchSequence` for testing - ✅ Added orphan-to-root fallback with clear documentation - ✅ Moved constants to fix linting issues - ✅ Implemented `findMessageCreationState` algorithm - ✅ Updated `messageMetadata` to use accurate creation state detection - ✅ Removed unused `findLastIndex` function ### `src/tests/branchSequence.test.ts` - ✅ New unit test verifying truncated histories produce non-empty trees ## Impact - **Before**: `fetchStateHistory: { limit: 5 }` → empty messages array + incorrect edit behavior - **After**: `fetchStateHistory: { limit: 5 }` → returns expected message list + safe editing only for messages with known parent checkpoints - **No breaking changes** - existing functionality unchanged - **Patch release** recommended ## Testing - [x] Build passes - [x] All existing tests pass - [x] New test covers the branch tree regression - [x] Lint clean - [x] Manual verification in production app - [x] Edit/regenerate buttons properly hidden for messages without reliable parent checkpoints Fixes empty message arrays and prevents incorrect branching when using `fetchStateHistory` limits. Twitter/X handle: `ibbyybuilds` --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
yindo added the pull-request label 2026-02-15 20:15:52 -05:00
yindo closed this issue 2026-02-15 20:15:52 -05:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: langchain-ai/langgraphjs#1468