Skip to content

fix(gateway): add freshness gate to resume_pending sessions - #46963

Closed
vanthinh6886 wants to merge 1 commit into
NousResearch:mainfrom
vanthinh6886:fix/resume-pending-stale-session
Closed

fix(gateway): add freshness gate to resume_pending sessions#46963
vanthinh6886 wants to merge 1 commit into
NousResearch:mainfrom
vanthinh6886:fix/resume-pending-stale-session

Conversation

@vanthinh6886

Copy link
Copy Markdown
Contributor

Fixes #46934

When the gateway restarts after a crash, sessions interrupted mid-turn are marked resume_pending=True. If the auto-recovery turn fails, resume_pending is never cleared. After the freshness window expires, these sessions become zombies — user-initiated messages resume the stale session with old conversation history, bypassing idle reset.

Root Cause

In gateway/session.py, get_or_create_session() returned resume_pending sessions unconditionally without checking if they were still fresh.

Fix

Add a freshness gate using last_resume_marked_at against HERMES_AUTO_CONTINUE_FRESHNESS window (default 3600s). If expired, fall through to auto-reset with reason "resume_pending_expired".

Before

elif entry.resume_pending:
    entry.updated_at = now
    self._save()
    return entry  # Always returns stale sessions

After

elif entry.resume_pending:
    _ref_time = entry.last_resume_marked_at or entry.updated_at
    if _fw > 0 and (now - _ref_time).total_seconds() > _fw:
        reset_reason = "resume_pending_expired"  # Fall through to reset
    else:
        entry.updated_at = now
        self._save()
        return entry

Respects HERMES_AUTO_CONTINUE_FRESHNESS=0 to disable the gate (opt-out for users who want the old behavior).

…ession

When a session has resume_pending=True but the freshness window has
expired (default 1 hour), the session is a zombie — the auto-recovery
turn either never ran or failed. Previously, get_or_create_session()
returned the stale session unconditionally, causing context bleed
where the agent would respond with old conversation context.

Fix: check last_resume_marked_at against HERMES_AUTO_CONTINUE_FRESHNESS
window. If expired, fall through to auto-reset with reason
"resume_pending_expired" instead of returning the stale entry.

Fixes NousResearch#46934
@teknium1

teknium1 commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Merged via #56264 (commit a1f62f4) — your commit was cherry-picked onto current main with your authorship preserved in git log. Thanks!

Note: the exact bug your PR targeted (the unconditional return entry in the resume_pending branch) was already partially addressed on main by #54442, which added _should_reset() there. But that idle/daily policy keys on updated_at, which is bumped on every message — so a zombie session that keeps receiving messages never trips it. Your freshness gate keys on last_resume_marked_at (set once, never bumped), which correctly catches that case. The salvage kept your mechanism and added a single-source-of-truth refactor of auto_continue_freshness_window() plus 3 tests.

@teknium1 teknium1 closed this Jul 1, 2026
crayfish-ai added a commit to crayfish-ai/hermes-agent that referenced this pull request Jul 26, 2026
When a session's resume_pending marker outlasts the freshness window,
the scheduler skips auto-resuming it but leaves the stale flag in
sessions.json. Over multiple restarts, these accumulate as zombie
entries. On startup, the scheduler now calls clear_resume_pending()
for each expired marker so it doesn't persist.

This is a defense-in-depth complement to the freshness gate in
get_or_create_session() (PR NousResearch#46963), which prevents stale sessions
from being served to users at message time. Together they close the
resume_pending residual accumulation loop.

Fixes NousResearch#46934
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/gateway Gateway runner, session dispatch, delivery P1 High — major feature broken, no workaround sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform sweeper:risk-session-state Sweeper risk: may lose/corrupt/mis-associate session or context state type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bug: stale resume_pending sessions bypass idle reset, causing context bleed after gateway restart

4 participants