Replace the tuple(list[dict], int) return of
Session.retain_recent_legal_suffix with a named RetentionResult
dataclass that exposes retained, dropped,
already_consolidated_count, and new_last_consolidated fields.
The tuple return was easy to misuse because the second value only
made sense relative to the first and the old last_consolidated
cursor. The named fields make the archive-skip semantics explicit
at every call site.
No behavior change. All existing tests pass unchanged in semantics.
Refs #4136
Signed-off-by: axelray-dev <110029405+axelray-dev@users.noreply.github.com>
Treat the current live user message as the replay boundary for normal user turns, while keeping user-turn extension for history and consolidation paths that need it. Add regression coverage for the user-triggered long tool-turn case.
The previous fix made retain_recent_legal_suffix return the actual dropped
message list, but already_consolidated was still computed with
min(before_last_consolidated, len(dropped)), which assumes dropped messages
are always a prefix. In the else branch (tail has no user messages), dropped
may include messages from after the consolidated prefix, causing
already_consolidated to skip too many and leaving tail messages neither
retained nor raw-archived.
Fix by having retain_recent_legal_suffix return (dropped,
already_consolidated_count) where already_consolidated_count is computed
against original message indices. Also fix last_consolidated update to count
how many retained messages were inside the old consolidated prefix.
When retain_recent_legal_suffix hits the else branch (tail has no user
messages), it takes a non-contiguous slice from the middle of the session.
enforce_file_cap incorrectly assumed dropped messages were always a prefix
(before[:dropped_count]), causing user messages to be both archived and
retained, and some messages to silently disappear.
Fix by having retain_recent_legal_suffix return the actual dropped message
list using identity-based diff, so enforce_file_cap no longer needs to
guess which messages were removed.
Align the WebUI sidebar and chat chrome with the updated design, and generate WebUI session titles asynchronously without blocking turns.
Co-authored-by: Cursor <cursoragent@cursor.com>
Past assistant turns in history were prefixed with "[Message Time: ...]"
just like user turns. The model treated these as in-context demos and
started prefixing its own replies with the same marker, leaking
metadata to the user. Prompt-level warnings could not beat dozens of
prior assistant samples.
Annotate only user turns and proactive deliveries
(_channel_delivery=True, i.e. cron / heartbeat pushes whose timing is
the whole point and which are too infrequent to act as demos). Adjacent
user-side timestamps still pin every normal assistant reply for
relative-time reasoning. The now-redundant identity.md warning is
removed along with the demonstration source.
Include persisted turn timestamps when assembling LLM prompts so relative-date references like yesterday and today have concrete anchors.
Made-with: Cursor