LibreChat/client
Danny Avila a9d99b3771
📌 fix: Keep the Settled Turn Mounted Through Final Content Compaction (#15186)
* 📌 fix: Keep the Settled Turn Mounted Through Final Content Compaction

The agent aggregator writes content parts at provider-source indexes, so
the streamed array is sparse wherever a step produced nothing; the final
SSE event carries the persisted, compacted array. Adopting it verbatim
shifted every part after a hole, re-keying every index-derived React
identity: the settled message remounted wholesale, activity-phase groups
replayed their fold-in entrance, code panes re-highlighted, and the
thread visibly snapped up and down at the end of every tool-calling run.

finalHandler now pairs the compacted parts with their streamed
counterparts in order and stamps each with the index it streamed at
(`streamedIndex`, client-only); render keys read the stamp while all
coordinate logic (edit indexes, phase bounds, cursor) stays on the live
compacted positions the server persisted. Phase-segment keys also anchor
to their first defined part instead of the segment ordinal, since
phantom hole-only segments vanish at compaction and shifted every
segment after them.

* 🔁 fix: Carry Identity Stamps Through Re-Delivered Finals and Parallel Attribution

Codex round 1, both real:
- P1: a later final event can re-deliver an already-settled message as a
  fresh compact array (Assistants runMessages resync); index-aligned
  pairing returned it unstamped, wiping the previous settle's stamps and
  re-keying the older turn all over again. The pairing now carries the
  matched current part's stamp forward, so a settled turn keeps its keys
  through every subsequent final.
- P2: ParallelContentRenderer's sequential stretches invoked
  renderResumeAttribution with only the live index, so steer attribution
  nodes in parallel content still re-keyed at the swap. The stable key
  index now threads through both call sites; getPartKeyIndex moves to
  utils/messages beside the stamp writer it reads.

* 🧿 fix: Require Content Agreement Before Pairing Streamed Identity

Codex round 2 (P2, real): hide_sequential_outputs runs omit intermediate
parts from the final array, so a type-only match could hand the retained
output an omitted intermediate's identity — transferring its key and any
UI state. Non-tool pairing now requires content agreement: mutual-prefix
text for TEXT/THINK/ACTIVITY_LABEL (one side extending the other is the
same part observed at two moments), the Open Responses phase for TEXT,
and the label kind for activity labels — a blank reservation still pairs
with its filled label. Ambiguous shapes fall back to the pre-stamp full
re-key, which is honest for a final that visibly removes parts.

* 🪢 fix: Refuse Stamping When the Server Removed Content; Strip Stamps on Edited Reruns

Codex round 3, two of three real:
- Prefix agreement alone still mis-paired when an omitted intermediate
  happened to prefix the retained output. Pairing now also requires that
  no substantial streamed part is left over: leftovers mean the server
  removed content (hide_sequential_outputs), so every in-order pairing
  is suspect and the message re-keys plainly instead.
- An edited resubmission clones the settled (stamped) prefix and appends
  the rerun's parts at the prefix length; a retained stamp at or above
  that length collides with an appended part's key. The clone now strips
  the client-only stamps, reverting the retained prefix to physical
  identity for the rerun.

The third finding (content-segment keys under late-phase recovery) is
declined with rationale on the PR: user expansion overrides survive via
the message-wide expansion map with stable group ids, recovery is a
genuine restructure at the moment a phase materializes, and first-child
anchoring is the only choice stable under the two high-frequency events
(streaming appends and final compaction).
2026-08-25 06:26:17 -04:00
..
public 🪢 feat: Langfuse Fanout Connection Setting (#14108) 2026-07-29 18:33:10 -04:00
scripts
src 📌 fix: Keep the Settled Turn Mounted Through Final Content Compaction (#15186) 2026-08-25 06:26:17 -04:00
sw 🛟 fix: Auto-Recover from Stale Service Worker Assets After Deploys (#13686) 2026-06-11 11:57:06 -04:00
test 🔒 chore: Upgrade react-router-dom to v7.18.2 (security) (#14582) 2026-08-01 17:19:52 -04:00
babel.config.cjs
check_updates.sh
index.html 📡 feat: add rum browser page-load diagnostics (#14106) 2026-07-05 11:32:53 -04:00
jest.config.cjs 🧮 fix: Currency-Safe Single-Dollar LaTeX via Micromark Tokenizer (#15181) 2026-08-24 22:29:02 -04:00
jest.resolver.cjs ⬆️ chore: Migrate off deprecated @ariakit/react-core to @ariakit/react-components (#13940) 2026-06-24 23:13:57 -04:00
nginx.conf 🐳 feat: Bundle Admin Panel in Docker Compose Stacks (#13876) 2026-06-22 16:59:08 -04:00
package.json 🧮 fix: Currency-Safe Single-Dollar LaTeX via Micromark Tokenizer (#15181) 2026-08-24 22:29:02 -04:00
postcss.config.cjs
tailwind.config.cjs feat: Context Gauge Hover Reveal and Breakdown Motion Polish (#15038) 2026-08-21 11:34:36 -04:00
tsconfig.json 👷 ci: Type-check the Client Workspace (#13560) 2026-06-06 18:40:31 -04:00
vite.config.ts 🎨 refactor: adopt the @librechat/client design system (semantic color tokens + component migration) (#13879) 2026-08-06 09:15:17 -04:00